X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=Novacoin%2FCBlockStore.cs;h=94fc2b67662143d9ae4db9f31ed2190fe2bbf9a5;hb=eb39142ad873e102405ceffb5ec837b510da9096;hp=a9c504cdfd310a048d42043a18c9adabc1e4bd26;hpb=7726cc3ff2ad58160957235de7c08f1e704c8532;p=NovacoinLibrary.git diff --git a/Novacoin/CBlockStore.cs b/Novacoin/CBlockStore.cs index a9c504c..94fc2b6 100644 --- a/Novacoin/CBlockStore.cs +++ b/Novacoin/CBlockStore.cs @@ -61,6 +61,11 @@ namespace Novacoin public uint nNonce { get; set; } /// + /// Next block hash. + /// + public byte[] nextHash { get; set; } + + /// /// Block type flags /// public BlockType BlockTypeFlag { get; set; } @@ -71,9 +76,14 @@ namespace Novacoin public long nStakeModifier { get; set; } /// - /// Stake entropy bit + /// Chain trust score + /// + public byte[] ChainTrust { get; set; } + + /// + /// Proof-of-Stake hash /// - public byte nEntropyBit { get; set; } + public byte[] hashProofOfStake { get; set; } /// /// Block height @@ -211,19 +221,45 @@ namespace Novacoin /// /// Previous block cursor /// - public public CBlockStoreItem prev { + [Ignore] + public CBlockStoreItem prev { get { return CBlockStore.Instance.GetCursor(prevHash); } } /// + /// Next block cursor + /// + [Ignore] + public CBlockStoreItem next + { + get { return CBlockStore.Instance.GetCursor(nextHash); } + } + + [Ignore] + bool IsInMainChain + { + get { return (next != null); } + } + + /// /// STake modifier generation flag /// + [Ignore] public bool GeneratedStakeModifier { get { return (BlockTypeFlag & BlockType.BLOCK_STAKE_MODIFIER) != 0; } } /// + /// Stake entropy bit + /// + [Ignore] + public uint StakeEntropyBit + { + get { return ((uint)(BlockTypeFlag & BlockType.BLOCK_STAKE_ENTROPY) >> 1); } + } + + /// /// Sets stake modifier and flag. /// /// New stake modifier. @@ -259,19 +295,143 @@ namespace Novacoin /// /// Block has no proof-of-stake flag. /// + [Ignore] public bool IsProofOfWork { - get { return (BlockTypeFlag & BlockType.BLOCK_PROOF_OF_STAKE) != 0; } + get { return (BlockTypeFlag & BlockType.BLOCK_PROOF_OF_STAKE) == 0; } } /// /// Block has proof-of-stake flag set. /// + [Ignore] public bool IsProofOfStake { - get { return (BlockTypeFlag & BlockType.BLOCK_PROOF_OF_STAKE) == 0; } + get { return (BlockTypeFlag & BlockType.BLOCK_PROOF_OF_STAKE) != 0; } } + /// + /// Chain trust score. + /// + [Ignore] + public uint256 nChainTrust { + get + { + if (ChainTrust.Length != 32) + { + byte[] tmp = ChainTrust; + Array.Resize(ref tmp, 32); + ChainTrust = tmp; + } + + return ChainTrust; + } + set { ChainTrust = Interop.TrimArray(value); } + } + + /// + /// Block trust score. + /// + [Ignore] + public uint256 nBlockTrust + { + get + { + uint256 nTarget = 0; + nTarget.Compact = nBits; + + /* Old protocol */ + if (nTime < NetUtils.nChainChecksSwitchTime) + { + return IsProofOfStake ? (new uint256(1) << 256) / (nTarget + 1) : 1; + } + + /* New protocol */ + + // Calculate work amount for block + var nPoWTrust = NetUtils.nPoWBase / (nTarget + 1); + + // Set nPowTrust to 1 if we are checking PoS block or PoW difficulty is too low + nPoWTrust = (IsProofOfStake || !nPoWTrust) ? 1 : nPoWTrust; + + // Return nPoWTrust for the first 12 blocks + if (prev == null || prev.nHeight < 12) + return nPoWTrust; + + CBlockStoreItem currentIndex = prev; + + if (IsProofOfStake) + { + var nNewTrust = (new uint256(1) << 256) / (nTarget + 1); + + // Return 1/3 of score if parent block is not the PoW block + if (!prev.IsProofOfWork) + { + return nNewTrust / 3; + } + + int nPoWCount = 0; + + // Check last 12 blocks type + while (prev.nHeight - currentIndex.nHeight < 12) + { + if (currentIndex.IsProofOfWork) + { + nPoWCount++; + } + currentIndex = currentIndex.prev; + } + + // Return 1/3 of score if less than 3 PoW blocks found + if (nPoWCount < 3) + { + return nNewTrust / 3; + } + + return nNewTrust; + } + else + { + var nLastBlockTrust = prev.nChainTrust - prev.prev.nChainTrust; + + // Return nPoWTrust + 2/3 of previous block score if two parent blocks are not PoS blocks + if (!prev.IsProofOfStake || !prev.prev.IsProofOfStake) + { + return nPoWTrust + (2 * nLastBlockTrust / 3); + } + + int nPoSCount = 0; + + // Check last 12 blocks type + while (prev.nHeight - currentIndex.nHeight < 12) + { + if (currentIndex.IsProofOfStake) + { + nPoSCount++; + } + currentIndex = currentIndex.prev; + } + + // Return nPoWTrust + 2/3 of previous block score if less than 7 PoS blocks found + if (nPoSCount < 7) + { + return nPoWTrust + (2 * nLastBlockTrust / 3); + } + + nTarget.Compact = prev.nBits; + + if (!nTarget) + { + return 0; + } + + var nNewTrust = (new uint256(1) << 256) / (nTarget + 1); + + // Return nPoWTrust + full trust score for previous block nBits + return nPoWTrust + nNewTrust; + } + } + } } @@ -422,6 +582,8 @@ namespace Novacoin fStreamReadWrite = File.Open(strBlockFile, FileMode.OpenOrCreate, FileAccess.ReadWrite); + Instance = this; + if (firstInit) { lock (LockObj) @@ -478,8 +640,6 @@ namespace Novacoin blockMap.TryAdd(item.Hash, item); } } - - Instance = this; } public bool GetTransaction(uint256 TxID, ref CTransaction tx) @@ -508,12 +668,23 @@ namespace Novacoin return false; } - // TODO: compute chain trust, set stake entropy bit, record proof-of-stake hash value + // Compute chain trust score + itemTemplate.nChainTrust = (itemTemplate.prev != null ? itemTemplate.prev.nChainTrust : 0) + itemTemplate.nBlockTrust; + + if (!itemTemplate.SetStakeEntropyBit(Entropy.GetStakeEntropyBit(itemTemplate.nHeight, blockHash))) + { + return false; // SetStakeEntropyBit() failed + } + + // TODO: set stake entropy bit, record proof-of-stake hash value // TODO: compute stake modifier // Add to index - itemTemplate.BlockTypeFlag = block.IsProofOfStake ? BlockType.PROOF_OF_STAKE : BlockType.PROOF_OF_WORK; + if (block.IsProofOfStake) + { + itemTemplate.SetProofOfStake(); + } if (!itemTemplate.WriteToFile(ref writer, ref block)) { @@ -603,7 +774,6 @@ namespace Novacoin var itemTemplate = new CBlockStoreItem() { nHeight = nHeight, - nEntropyBit = Entropy.GetStakeEntropyBit(nHeight, nHash) }; itemTemplate.FillHeader(block.header);