From eb39142ad873e102405ceffb5ec837b510da9096 Mon Sep 17 00:00:00 2001 From: CryptoManiac Date: Thu, 3 Sep 2015 22:59:58 +0300 Subject: [PATCH] Chain trust score computation. --- Novacoin/CBlockStore.cs | 164 +++++++++++++++++++++++++++++++++++++++++++---- Novacoin/Interop.cs | 14 ++++ NovacoinTest/Program.cs | 4 +- 3 files changed, 167 insertions(+), 15 deletions(-) diff --git a/Novacoin/CBlockStore.cs b/Novacoin/CBlockStore.cs index a579898..94fc2b6 100644 --- a/Novacoin/CBlockStore.cs +++ b/Novacoin/CBlockStore.cs @@ -76,9 +76,9 @@ namespace Novacoin public long nStakeModifier { get; set; } /// - /// Stake entropy bit + /// Chain trust score /// - public byte nEntropyBit { get; set; } + public byte[] ChainTrust { get; set; } /// /// Proof-of-Stake hash @@ -221,6 +221,7 @@ namespace Novacoin /// /// Previous block cursor /// + [Ignore] public CBlockStoreItem prev { get { return CBlockStore.Instance.GetCursor(prevHash); } } @@ -228,25 +229,31 @@ namespace Novacoin /// /// Next block cursor /// + [Ignore] public CBlockStoreItem next { get { return CBlockStore.Instance.GetCursor(nextHash); } } + [Ignore] bool IsInMainChain { get { return (next != null); } } - - /// - /// STake modifier generation flag - /// - public bool GeneratedStakeModifier + /// + /// 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); } @@ -288,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; + } + } + } } @@ -451,6 +582,8 @@ namespace Novacoin fStreamReadWrite = File.Open(strBlockFile, FileMode.OpenOrCreate, FileAccess.ReadWrite); + Instance = this; + if (firstInit) { lock (LockObj) @@ -507,8 +640,6 @@ namespace Novacoin blockMap.TryAdd(item.Hash, item); } } - - Instance = this; } public bool GetTransaction(uint256 TxID, ref CTransaction tx) @@ -537,7 +668,15 @@ 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 @@ -635,7 +774,6 @@ namespace Novacoin var itemTemplate = new CBlockStoreItem() { nHeight = nHeight, - nEntropyBit = Entropy.GetStakeEntropyBit(nHeight, nHash) }; itemTemplate.FillHeader(block.header); diff --git a/Novacoin/Interop.cs b/Novacoin/Interop.cs index 0cb7e75..55979d7 100644 --- a/Novacoin/Interop.cs +++ b/Novacoin/Interop.cs @@ -82,6 +82,20 @@ namespace Novacoin return bytes; } + public static byte[] TrimArray(byte[] bytes) + { + int trimStart = bytes.Length - 1; + while (trimStart >= 0 && bytes[trimStart] == 0) + { + trimStart--; + } + + byte[] result = new byte[trimStart + 1]; + Array.Copy(bytes, 0, result, 0, trimStart + 1); + + return result; + } + public static string ToHex(byte[] bytes) { var sb = new StringBuilder(); diff --git a/NovacoinTest/Program.cs b/NovacoinTest/Program.cs index c8295c2..7483d4b 100644 --- a/NovacoinTest/Program.cs +++ b/NovacoinTest/Program.cs @@ -12,6 +12,7 @@ namespace NovacoinTest { static void Main(string[] args) { +#if false /// Transaction decoding/encoding tests string strUserTx = "0100000078b4c95306340d96b77ec4ee9d42b31cadc2fab911e48d48c36274d516f226d5e85bbc512c010000006b483045022100c8df1fc17b6ea1355a39b92146ec67b3b53565e636e028010d3a8a87f6f805f202203888b9b74df03c3960773f2a81b2dfd1efb08bb036a8f3600bd24d5ed694cd5a0121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffff364c640420de8fa77313475970bf09ce4d0b1f8eabb8f1d6ea49d90c85b202ee010000006b483045022100b651bf3a6835d714d2c990c742136d769258d0170c9aac24803b986050a8655b0220623651077ff14b0a9d61e30e30f2c15352f70491096f0ec655ae1c79a44e53aa0121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffff7adbd5f2e521f567bfea2cb63e65d55e66c83563fe253464b75184a5e462043d000000006a4730440220183609f2b995993acc9df241aff722d48b9a731b0cd376212934565723ed81f00220737e7ce75ef39bdc061d0dcdba3ee24e43b899696a7c96803cee0a79e1f78ecb0121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffff999eb03e00a41c2f9fde8865a554ceebbc48d30f4c8ba22dd88da8c9b46fa920030000006b483045022100ec1ab104ef086ba79b0f2611ebf1bfdd22a7a1020f6630fa1c6707546626e0db022056093d4048a999392185ccc735ef736a5497bd68f60b42e6c0c93ba770b54d010121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffffc0543b86be257ddd85b014a76718a70fab9eaa3c477460e4ca187094d86f369c0500000069463043021f24275c72f952043174daf01d7f713f878625f0522124a3cab48a0a2e12604202201b47742e6697b0ebdd1e4ba49c74baf142a0228ad0e0ee847488994c9dce78470121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffffe1793d4519147782293dd1db6d90e461265d91db2cc6889c37209394d42ad10d050000006a473044022018a0c3d73b2765d75380614ab36ee8e3c937080894a19166128b1e3357b208fb0220233c9609985f535547381431526867ad0255ec4969afe5c360544992ed6b3ed60121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4cffffffff02e5420000000000001976a91457d84c814b14bd86bf32f106b733baa693db7dc788ac409c0000000000001976a91408c8768d5d6bf7c1d9609da4e766c3f1752247b188ac00000000"; @@ -313,12 +314,11 @@ namespace NovacoinTest 1b138d5e 0000000000136944000000000000000000000000000000000000000000000000 */ +#endif Console.WriteLine("Reading the block file..."); var bs = new CBlockStore(); bs.ParseBlockFile(); - - Console.ReadLine(); } } } -- 1.7.1