示例#1
0
		public static async Task<MnemonicReference> ParseAsync
			(ChainBase chain,
			IBlockRepository blockRepository,
			Wordlist wordList,
			string sentence)
		{
			var w = wordList.GetWords(sentence).Length;
			var finalAddress = wordList.ToBits(sentence);
			var rawAddress = DecryptFinalAddress(finalAddress);

			int blockHeight;
			int x = DecodeBlockHeight(rawAddress, out blockHeight);

			var header = chain.GetBlock(blockHeight);
			if(header == null)
				throw new InvalidBrainAddressException("This block does not exists");
			var block = await blockRepository.GetBlockAsync(header.HashBlock).ConfigureAwait(false);
			if(block == null || block.GetHash() != header.HashBlock)
				throw new InvalidBrainAddressException("This block does not exists");

			int y1 = BitCount((int)block.Transactions.Count);
			int y2 = 11 * w - 1 - x - c;
			int y = Math.Min(y1, y2);
			int txIndex = Decode(Substring(rawAddress, x, y));
			if(txIndex >= block.Transactions.Count)
				throw new InvalidBrainAddressException("The Transaction Index is out of the bound of the block");

			var transaction = block.Transactions[(int)txIndex];
			return Parse(chain, wordList, sentence, transaction, block);
		}
示例#2
0
 public ChainedBlock FindFork(ChainBase chain)
 {
     if (chain == null)
     {
         throw new ArgumentNullException("chain");
     }
     return(FindFork(chain.ToEnumerable(true).Select(o => o.HashBlock)));
 }
示例#3
0
 public ChainedBlock SetTip(ChainBase otherChain)
 {
     if (otherChain == null)
     {
         throw new ArgumentNullException("otherChain");
     }
     return(SetTip(otherChain.Tip));
 }
示例#4
0
 /// <summary>
 /// Returns the first common block between two chains
 /// </summary>
 /// <param name="chain">The other chain</param>
 /// <returns>First common block or null</returns>
 public ChainedBlock FindFork(ChainBase chain)
 {
     if (chain == null)
     {
         throw new ArgumentNullException(nameof(chain));
     }
     return(FindFork(chain.Tip.EnumerateToGenesis().Select(o => o.HashBlock)));
 }
示例#5
0
 public bool SameTip(ChainBase chain)
 {
     if (chain == null)
     {
         throw new ArgumentNullException("chain");
     }
     return(Tip.HashBlock == chain.Tip.HashBlock);
 }
示例#6
0
        /// <summary>
        /// Sets the tip of this chain to the tip of another chain.
        /// </summary>
        /// <param name="otherChain">The other chain whose tip to apply to this chain.</param>
        /// <returns>The new tip.</returns>
        public ChainedHeader SetTip(ChainBase otherChain)
        {
            if (otherChain == null)
            {
                throw new ArgumentNullException("otherChain");
            }

            return(this.SetTip(otherChain.Tip));
        }
示例#7
0
 public static MnemonicReference Parse
     (ChainBase chain,
     Wordlist wordList,
     string sentence,
     Transaction transaction,
     Block block)
 {
     return(Parse(chain, wordList, sentence, transaction, block.Filter(transaction.GetHash())));
 }
示例#8
0
		/// <summary>
		/// 
		/// </summary>
		/// <param name="chain"></param>
		/// <param name="blockRepository"></param>
		/// <param name="blockHeight"></param>
		/// <param name="txIndex"></param>
		/// <param name="txOutIndex"></param>
		/// <exception cref="NBitcoin.InvalidBrainAddressException"></exception>
		/// <returns></returns>
		public static async Task<MnemonicReference> CreateAsync
			(ChainBase chain,
			IBlockRepository blockRepository,
			int blockHeight, int txIndex, int txOutIndex)
		{
			var header = chain.GetBlock(blockHeight);
			if(header == null)
				throw new InvalidBrainAddressException("This block does not exists");
			var block = await blockRepository.GetBlockAsync(header.HashBlock).ConfigureAwait(false);
			if(block == null || block.GetHash() != header.HashBlock)
				throw new InvalidBrainAddressException("This block does not exists");
			return Create(chain, block, blockHeight, txIndex, txOutIndex);
		}
示例#9
0
        public const uint ModifierInterval     = 10 * 60; // time to elapse before new modifier is computed

        public static bool CheckAndComputeStake(IBlockRepository blockStore, ITransactionRepository trasnactionStore, IBlockTransactionMapStore mapStore, StakeChain stakeChain,
                                                ChainBase chainIndex, ChainedBlock pindex, Block block, out BlockStake blockStake)
        {
            if (block.GetHash() != pindex.HashBlock)
            {
                throw new ArgumentException();
            }

            blockStake = new BlockStake(block);

            uint256 hashProof = null;

            // Verify hash target and signature of coinstake tx
            if (BlockStake.IsProofOfStake(block))
            {
                var pindexPrev = pindex.Previous;

                var prevBlockStake = stakeChain.Get(pindexPrev.HashBlock);
                if (prevBlockStake == null)
                {
                    return(false);                    // the stake proof of the previous block is not set
                }
                uint256 targetProofOfStake;
                if (!CheckProofOfStake(blockStore, trasnactionStore, mapStore, pindexPrev, prevBlockStake, block.Transactions[1],
                                       pindex.Header.Bits.ToCompact(), out hashProof, out targetProofOfStake))
                {
                    return(false);                    // error("AcceptBlock() : check proof-of-stake failed for block %s", hash.ToString());
                }
            }

            // PoW is checked in CheckBlock()
            if (BlockStake.IsProofOfWork(block))
            {
                hashProof = pindex.Header.GetPoWHash();
            }

            // todo: is this the same as chain work?
            // compute chain trust score
            //pindexNew.nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + pindexNew->GetBlockTrust();

            // compute stake entropy bit for stake modifier
            if (!blockStake.SetStakeEntropyBit(blockStake.GetStakeEntropyBit()))
            {
                return(false);                //error("AddToBlockIndex() : SetStakeEntropyBit() failed");
            }
            // Record proof hash value
            blockStake.HashProof = hashProof;

            // compute stake modifier
            return(ComputeStakeModifier(chainIndex, pindex, blockStake, stakeChain));
        }
示例#10
0
		public static MnemonicReference Create
			(
			ChainBase chain,
			Block block,
			int blockHeight,
			int txIndex,
			int txOutIndex)
		{
			var header = chain.GetBlock(blockHeight);
			if(header == null || block.GetHash() != header.HashBlock)
				throw new InvalidBrainAddressException("This block does not exists");
			if(txIndex >= block.Transactions.Count)
				throw new InvalidBrainAddressException("The Transaction Index is out of the bound of the block");
			var transaction = block.Transactions[txIndex];
			return Create(chain, transaction, block, txOutIndex);
		}
示例#11
0
        public static bool ComputeStakeModifier(ChainBase chainIndex, ChainedBlock pindex)
        {
            var pindexPrev = pindex.Previous;

            // compute stake modifier
            ulong nStakeModifier;
            bool  fGeneratedStakeModifier;

            if (!ComputeNextStakeModifier(chainIndex, pindexPrev, out nStakeModifier, out fGeneratedStakeModifier))
            {
                return(false);                //error("AddToBlockIndex() : ComputeNextStakeModifier() failed");
            }
            pindex.Header.PosParameters.SetStakeModifier(nStakeModifier, fGeneratedStakeModifier);
            pindex.Header.PosParameters.StakeModifierV2 = ComputeStakeModifierV2(
                pindexPrev, pindex.Header.PosParameters.IsProofOfWork() ? pindex.HashBlock : pindex.Header.PosParameters.PrevoutStake.Hash);

            return(true);
        }
示例#12
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="chain"></param>
        /// <param name="blockRepository"></param>
        /// <param name="blockHeight"></param>
        /// <param name="txIndex"></param>
        /// <param name="txOutIndex"></param>
        /// <exception cref="NBitcoin.InvalidBrainAddressException"></exception>
        /// <returns></returns>
        public static async Task <MnemonicReference> CreateAsync
            (ChainBase chain,
            IBlockRepository blockRepository,
            int blockHeight, int txIndex, int txOutIndex)
        {
            var header = chain.GetBlock(blockHeight);

            if (header == null)
            {
                throw new InvalidBrainAddressException("This block does not exists");
            }
            var block = await blockRepository.GetBlockAsync(header.HashBlock).ConfigureAwait(false);

            if (block == null || block.GetHash() != header.HashBlock)
            {
                throw new InvalidBrainAddressException("This block does not exists");
            }
            return(Create(chain, block, blockHeight, txIndex, txOutIndex));
        }
示例#13
0
        public static bool ComputeStakeModifier(ChainBase chainIndex, ChainedBlock pindex, BlockStake blockStake, StakeChain stakeChain)
        {
            var pindexPrev     = pindex.Previous;
            var blockStakePrev = pindexPrev == null ? null : stakeChain.Get(pindexPrev.HashBlock);

            // compute stake modifier
            ulong nStakeModifier;
            bool  fGeneratedStakeModifier;

            if (!ComputeNextStakeModifier(stakeChain, chainIndex, pindexPrev, out nStakeModifier, out fGeneratedStakeModifier))
            {
                return(false);                //error("AddToBlockIndex() : ComputeNextStakeModifier() failed");
            }
            blockStake.SetStakeModifier(nStakeModifier, fGeneratedStakeModifier);
            blockStake.StakeModifierV2 = ComputeStakeModifierV2(
                pindexPrev, blockStakePrev, blockStake.IsProofOfWork() ? pindex.HashBlock : blockStake.PrevoutStake.Hash);

            return(true);
        }
示例#14
0
        public static async Task <MnemonicReference> ParseAsync
            (ChainBase chain,
            IBlockRepository blockRepository,
            Wordlist wordList,
            string sentence)
        {
            var w            = wordList.GetWords(sentence).Length;
            var finalAddress = wordList.ToBits(sentence);
            var rawAddress   = DecryptFinalAddress(finalAddress);

            int blockHeight;
            int x = DecodeBlockHeight(rawAddress, out blockHeight);

            var header = chain.GetBlock(blockHeight);

            if (header == null)
            {
                throw new InvalidBrainAddressException("This block does not exists");
            }
            var block = await blockRepository.GetBlockAsync(header.HashBlock).ConfigureAwait(false);

            if (block == null || block.GetHash() != header.HashBlock)
            {
                throw new InvalidBrainAddressException("This block does not exists");
            }

            int y1      = BitCount((int)block.Transactions.Count);
            int y2      = 11 * w - 1 - x - c;
            int y       = Math.Min(y1, y2);
            int txIndex = Decode(Substring(rawAddress, x, y));

            if (txIndex >= block.Transactions.Count)
            {
                throw new InvalidBrainAddressException("The Transaction Index is out of the bound of the block");
            }

            var transaction = block.Transactions[(int)txIndex];

            return(Parse(chain, wordList, sentence, transaction, block));
        }
示例#15
0
        public static MnemonicReference Create
        (
            ChainBase chain,
            Block block,
            int blockHeight,
            int txIndex,
            int txOutIndex)
        {
            var header = chain.GetBlock(blockHeight);

            if (header == null || block.GetHash() != header.HashBlock)
            {
                throw new InvalidBrainAddressException("This block does not exists");
            }
            if (txIndex >= block.Transactions.Count)
            {
                throw new InvalidBrainAddressException("The Transaction Index is out of the bound of the block");
            }
            var transaction = block.Transactions[txIndex];

            return(Create(chain, transaction, block, txOutIndex));
        }
示例#16
0
        public static MnemonicReference Parse
            (ChainBase chain,
            Wordlist wordList,
            string sentence,
            Transaction transaction,
            MerkleBlock merkleBlock)
        {
            var indices = wordList.ToIndices(sentence);

            //Step1: Determine w = number of words in the mnemonic code
            int w = indices.Length;

            //Convert mnemonic code into finalAddress following BIP-0039
            var finalAddress = Wordlist.ToBits(indices);

            var rawAddress  = DecryptFinalAddress(finalAddress);
            int blockHeight = 0;
            var x           = DecodeBlockHeight(rawAddress, out blockHeight);

            var header = chain.GetBlock((int)blockHeight);

            if (header == null)
            {
                throw new InvalidBrainAddressException("This block does not exists");
            }
            if (header.HashBlock != merkleBlock.Header.GetHash())
            {
                throw new InvalidBrainAddressException("The provided merkleblock do not match the block of the sentence");
            }
            var        blockId = header.HashBlock;
            MerkleNode root    = merkleBlock.PartialMerkleTree.TryGetMerkleRoot();

            if (root == null || root.Hash != header.Header.HashMerkleRoot)
            {
                throw new InvalidBrainAddressException("Invalid partial merkle tree");
            }

            int y1      = BitCount((int)merkleBlock.PartialMerkleTree.TransactionCount);
            int y2      = 11 * w - 1 - x - c;
            int y       = Math.Min(y1, y2);
            int txIndex = Decode(Substring(rawAddress, x, y));

            var txLeaf = root.GetLeafs().Skip((int)txIndex).FirstOrDefault();

            if (txLeaf == null || txLeaf.Hash != transaction.GetHash())
            {
                throw new InvalidBrainAddressException("The transaction do not appear in the block");
            }

            int z1          = BitCount(transaction.Outputs.Count);
            int z2          = 11 * w - 1 - x - y - c;
            int z           = Math.Min(z1, z2);
            int outputIndex = Decode(Substring(rawAddress, x + y, z));

            if (outputIndex >= transaction.Outputs.Count)
            {
                throw new InvalidBrainAddressException("The specified txout index is outside of the transaction bounds");
            }
            var txOut = transaction.Outputs[outputIndex];


            var cs               = 11 * w - 1 - x - y - z;
            var actualChecksum   = Substring(rawAddress, x + y + z, cs);
            var expectedChecksum = CalculateChecksum(blockId, txIndex, outputIndex, txOut.ScriptPubKey, cs);

            if (!actualChecksum.OfType <bool>().SequenceEqual(expectedChecksum.OfType <bool>()))
            {
                throw new InvalidBrainAddressException("Invalid checksum");
            }

            return(new MnemonicReference()
            {
                BlockHeight = (int)blockHeight,
                TransactionIndex = (int)txIndex,
                WordIndices = indices,
                Checksum = actualChecksum,
                Output = transaction.Outputs[outputIndex],
                OutputIndex = (int)outputIndex,
                BlockId = blockId,
                Transaction = transaction
            });
        }
示例#17
0
		public static MnemonicReference Parse
			(ChainBase chain,
			Wordlist wordList,
			string sentence,
			Transaction transaction,
			MerkleBlock merkleBlock)
		{
			var indices = wordList.ToIndices(sentence);

			//Step1: Determine w = number of words in the mnemonic code 
			int w = indices.Length;

			//Convert mnemonic code into finalAddress following BIP-0039
			var finalAddress = Wordlist.ToBits(indices);

			var rawAddress = DecryptFinalAddress(finalAddress);
			int blockHeight = 0;
			var x = DecodeBlockHeight(rawAddress, out blockHeight);

			var header = chain.GetBlock((int)blockHeight);
			if(header == null)
				throw new InvalidBrainAddressException("This block does not exists");
			if(header.HashBlock != merkleBlock.Header.GetHash())
				throw new InvalidBrainAddressException("The provided merkleblock do not match the block of the sentence");
			var blockId = header.HashBlock;
			MerkleNode root = merkleBlock.PartialMerkleTree.TryGetMerkleRoot();
			if(root == null || root.Hash != header.Header.HashMerkleRoot)
				throw new InvalidBrainAddressException("Invalid partial merkle tree");

			int y1 = BitCount((int)merkleBlock.PartialMerkleTree.TransactionCount);
			int y2 = 11 * w - 1 - x - c;
			int y = Math.Min(y1, y2);
			int txIndex = Decode(Substring(rawAddress, x, y));

			var txLeaf = root.GetLeafs().Skip((int)txIndex).FirstOrDefault();
			if(txLeaf == null || txLeaf.Hash != transaction.GetHash())
				throw new InvalidBrainAddressException("The transaction do not appear in the block");

			int z1 = BitCount(transaction.Outputs.Count);
			int z2 = 11 * w - 1 - x - y - c;
			int z = Math.Min(z1, z2);
			int outputIndex = Decode(Substring(rawAddress, x + y, z));

			if(outputIndex >= transaction.Outputs.Count)
				throw new InvalidBrainAddressException("The specified txout index is outside of the transaction bounds");
			var txOut = transaction.Outputs[outputIndex];


			var cs = 11 * w - 1 - x - y - z;
			var actualChecksum = Substring(rawAddress, x + y + z, cs);
			var expectedChecksum = CalculateChecksum(blockId, txIndex, outputIndex, txOut.ScriptPubKey, cs);

			if(!actualChecksum.OfType<bool>().SequenceEqual(expectedChecksum.OfType<bool>()))
				throw new InvalidBrainAddressException("Invalid checksum");

			return new MnemonicReference()
			{
				BlockHeight = (int)blockHeight,
				TransactionIndex = (int)txIndex,
				WordIndices = indices,
				Checksum = actualChecksum,
				Output = transaction.Outputs[outputIndex],
				OutputIndex = (int)outputIndex,
				BlockId = blockId,
				Transaction = transaction
			};
		}
示例#18
0
		public static MnemonicReference Parse
			(ChainBase chain,
			Wordlist wordList,
			string sentence,
			Transaction transaction,
			Block block)
		{
			return Parse(chain, wordList, sentence, transaction, block.Filter(transaction.GetHash()));
		}
示例#19
0
		public static MnemonicReference Create
			(ChainBase chain,
			Transaction transaction,
			MerkleBlock merkleBlock,
			int txOutIndex)
		{
			var blockId = merkleBlock.Header.GetHash();
			var merkleRoot = merkleBlock.PartialMerkleTree.TryGetMerkleRoot();
			if(merkleRoot == null || merkleRoot.Hash != merkleBlock.Header.HashMerkleRoot)
				throw new InvalidBrainAddressException("Invalid merkle block");
			if(txOutIndex >= transaction.Outputs.Count)
				throw new InvalidBrainAddressException("The specified txout index is outside of the transaction bounds");
			var matchedLeaf = merkleRoot.GetLeafs().Select((node, index) => new
			{
				node,
				index
			}).FirstOrDefault(_ => _.node.Hash == transaction.GetHash());
			if(matchedLeaf == null)
				throw new InvalidBrainAddressException("Transaction not included in this merkle block");

			var chainedHeader = chain.GetBlock(blockId);
			if(chainedHeader == null)
				throw new InvalidBrainAddressException("The block provided is not in the current chain");
			var blockHeight = chainedHeader.Height;
			var txIndex = matchedLeaf.index;
			var txOut = transaction.Outputs[txOutIndex];
			var block = chain.GetBlock(blockId);


			BitArray encodedBlockHeight = EncodeBlockHeight(blockHeight);
			int x = encodedBlockHeight.Length;

			//ymin = ceiling(log(txIndex + 1, 2))
			int ymin = BitCount(txIndex + 1);
			//zmin = ceiling(log(outputIndex + 1, 2))
			int zmin = BitCount(txOutIndex + 1);

			//w = ceiling((x + ymin + zmin + c + 1)/11)
			int w = RoundTo(x + ymin + zmin + c + 1, 11) / 11;
			int y = 0;
			int z = 0;
			for( ; ; w++)
			{
				int y1 = BitCount((int)merkleBlock.PartialMerkleTree.TransactionCount);
				int y2 = 11 * w - 1 - x - c;
				y = Math.Min(y1, y2);
				if(ymin > y)
					continue;
				int z1 = BitCount(transaction.Outputs.Count);
				int z2 = 11 * w - 1 - x - y - c;
				z = Math.Min(z1, z2);
				if(zmin > z)
					continue;
				break;
			}

			var cs = 11 * w - 1 - x - y - z;
			var checksum = CalculateChecksum(blockId, txIndex, txOutIndex, txOut.ScriptPubKey, cs);

			var rawAddress = Concat(encodedBlockHeight, Encode(txIndex, y), Encode(txOutIndex, z), checksum);

			var finalAddress = EncryptRawAddress(rawAddress);

			return new MnemonicReference()
			{
				BlockHeight = blockHeight,
				TransactionIndex = txIndex,
				OutputIndex = txOutIndex,
				Checksum = checksum,
				WordIndices = Wordlist.ToIntegers(finalAddress),
				Output = transaction.Outputs[txOutIndex],
				Transaction = transaction,
				BlockId = blockId
			};
		}
 public void SynchronizeChain(ChainBase chain)
 {
     if(chain.Tip != null && chain.Genesis.HashBlock != Configuration.Network.GetGenesis().GetHash())
         throw new ArgumentException("Incompatible Network between the indexer and the chain", "chain");
     if(chain.Tip == null)
         chain.SetTip(new ChainedBlock(Configuration.Network.GetGenesis().Header, 0));
     GetChainChangesUntilFork(chain.Tip, false)
         .UpdateChain(chain);
 }
示例#21
0
		public ChainedBlock SetTip(ChainBase otherChain)
		{
			if(otherChain == null)
				throw new ArgumentNullException("otherChain");
			return SetTip(otherChain.Tip);
		}
示例#22
0
 public ChainedBlock SetTip(ChainBase otherChain)
 {
     return(SetTip(otherChain.Tip));
 }
示例#23
0
 public static MnemonicReference Create(ChainBase chain, Transaction transaction, Block block, int txOutIndex)
 {
     return(Create(chain, transaction, block.Filter(transaction.GetHash()), txOutIndex));
 }
示例#24
0
		public bool SameTip(ChainBase chain)
		{
			if(chain == null)
				throw new ArgumentNullException("chain");
			return Tip.HashBlock == chain.Tip.HashBlock;
		}
示例#25
0
        public static MnemonicReference Create
            (ChainBase chain,
            Transaction transaction,
            MerkleBlock merkleBlock,
            int txOutIndex)
        {
            var blockId    = merkleBlock.Header.GetHash();
            var merkleRoot = merkleBlock.PartialMerkleTree.TryGetMerkleRoot();

            if (merkleRoot == null || merkleRoot.Hash != merkleBlock.Header.HashMerkleRoot)
            {
                throw new InvalidBrainAddressException("Invalid merkle block");
            }
            if (txOutIndex >= transaction.Outputs.Count)
            {
                throw new InvalidBrainAddressException("The specified txout index is outside of the transaction bounds");
            }
            var matchedLeaf = merkleRoot.GetLeafs().Select((node, index) => new
            {
                node,
                index
            }).FirstOrDefault(_ => _.node.Hash == transaction.GetHash());

            if (matchedLeaf == null)
            {
                throw new InvalidBrainAddressException("Transaction not included in this merkle block");
            }

            var chainedHeader = chain.GetBlock(blockId);

            if (chainedHeader == null)
            {
                throw new InvalidBrainAddressException("The block provided is not in the current chain");
            }
            var blockHeight = chainedHeader.Height;
            var txIndex     = matchedLeaf.index;
            var txOut       = transaction.Outputs[txOutIndex];
            var block       = chain.GetBlock(blockId);


            BitArray encodedBlockHeight = EncodeBlockHeight(blockHeight);
            int      x = encodedBlockHeight.Length;

            //ymin = ceiling(log(txIndex + 1, 2))
            int ymin = BitCount(txIndex + 1);
            //zmin = ceiling(log(outputIndex + 1, 2))
            int zmin = BitCount(txOutIndex + 1);

            //w = ceiling((x + ymin + zmin + c + 1)/11)
            int w = RoundTo(x + ymin + zmin + c + 1, 11) / 11;
            int y = 0;
            int z = 0;

            for ( ; ; w++)
            {
                int y1 = BitCount((int)merkleBlock.PartialMerkleTree.TransactionCount);
                int y2 = 11 * w - 1 - x - c;
                y = Math.Min(y1, y2);
                if (ymin > y)
                {
                    continue;
                }
                int z1 = BitCount(transaction.Outputs.Count);
                int z2 = 11 * w - 1 - x - y - c;
                z = Math.Min(z1, z2);
                if (zmin > z)
                {
                    continue;
                }
                break;
            }

            var cs       = 11 * w - 1 - x - y - z;
            var checksum = CalculateChecksum(blockId, txIndex, txOutIndex, txOut.ScriptPubKey, cs);

            var rawAddress = Concat(encodedBlockHeight, Encode(txIndex, y), Encode(txOutIndex, z), checksum);

            var finalAddress = EncryptRawAddress(rawAddress);

            return(new MnemonicReference()
            {
                BlockHeight = blockHeight,
                TransactionIndex = txIndex,
                OutputIndex = txOutIndex,
                Checksum = checksum,
                WordIndices = Wordlist.ToIntegers(finalAddress),
                Output = transaction.Outputs[txOutIndex],
                Transaction = transaction,
                BlockId = blockId
            });
        }
示例#26
0
        // Stake Modifier (hash modifier of proof-of-stake):
        // The purpose of stake modifier is to prevent a txout (coin) owner from
        // computing future proof-of-stake generated by this txout at the time
        // of transaction confirmation. To meet kernel protocol, the txout
        // must hash with a future stake modifier to generate the proof.
        // Stake modifier consists of bits each of which is contributed from a
        // selected block of a given block group in the past.
        // The selection of a block is based on a hash of the block's proof-hash and
        // the previous stake modifier.
        // Stake modifier is recomputed at a fixed time interval instead of every
        // block. This is to make it difficult for an attacker to gain control of
        // additional bits in the stake modifier, even after generating a chain of
        // blocks.
        private static bool ComputeNextStakeModifier(StakeChain stakeChain, ChainBase chainIndex, ChainedBlock pindexPrev, out ulong nStakeModifier,
                                                     out bool fGeneratedStakeModifier)
        {
            nStakeModifier          = 0;
            fGeneratedStakeModifier = false;
            if (pindexPrev == null)
            {
                fGeneratedStakeModifier = true;
                return(true);                // genesis block's modifier is 0
            }

            // First find current stake modifier and its generation block time
            // if it's not old enough, return the same stake modifier
            long nModifierTime = 0;

            if (!GetLastStakeModifier(stakeChain, pindexPrev, out nStakeModifier, out nModifierTime))
            {
                return(false);                //error("ComputeNextStakeModifier: unable to get last modifier");
            }
            //LogPrint("stakemodifier", "ComputeNextStakeModifier: prev modifier=0x%016x time=%s\n", nStakeModifier, DateTimeStrFormat(nModifierTime));
            if (nModifierTime / ModifierInterval >= pindexPrev.Header.Time / ModifierInterval)
            {
                return(true);
            }

            // Sort candidate blocks by timestamp
            var  sortedByTimestamp       = new SortedDictionary <uint, uint256>();
            long nSelectionInterval      = GetStakeModifierSelectionInterval();
            long nSelectionIntervalStart = (pindexPrev.Header.Time / ModifierInterval) * ModifierInterval - nSelectionInterval;
            var  pindex = pindexPrev;

            while (pindex != null && pindex.Header.Time >= nSelectionIntervalStart)
            {
                sortedByTimestamp.Add(pindex.Header.Time, pindex.HashBlock);
                pindex = pindex.Previous;
            }
            int nHeightFirstCandidate = pindex?.Height + 1 ?? 0;

            // Select 64 blocks from candidate blocks to generate stake modifier
            ulong nStakeModifierNew      = 0;
            long  nSelectionIntervalStop = nSelectionIntervalStart;
            var   mapSelectedBlocks      = new Dictionary <uint256, ChainedBlock>();

            for (int nRound = 0; nRound < Math.Min(64, sortedByTimestamp.Count); nRound++)
            {
                // add an interval section to the current selection round
                nSelectionIntervalStop += GetStakeModifierSelectionIntervalSection(nRound);

                // select a block from the candidates of current round
                if (!SelectBlockFromCandidates(stakeChain, pindexPrev, sortedByTimestamp, mapSelectedBlocks, nSelectionIntervalStop, nStakeModifier, out pindex))
                {
                    return(false);                    // error("ComputeNextStakeModifier: unable to select block at round %d", nRound);
                }
                // write the entropy bit of the selected block
                var blockStake = stakeChain.Get(pindex.HashBlock);
                nStakeModifierNew |= ((ulong)blockStake.GetStakeEntropyBit() << nRound);

                // add the selected block from candidates to selected list
                mapSelectedBlocks.Add(pindex.HashBlock, pindex);

                //LogPrint("stakemodifier", "ComputeNextStakeModifier: selected round %d stop=%s height=%d bit=%d\n", nRound, DateTimeStrFormat(nSelectionIntervalStop), pindex->nHeight, pindex->GetStakeEntropyBit());
            }

            //  // Print selection map for visualization of the selected blocks
            //  if (LogAcceptCategory("stakemodifier"))
            //  {
            //      string strSelectionMap = "";
            //      '-' indicates proof-of-work blocks not selected
            //      strSelectionMap.insert(0, pindexPrev->nHeight - nHeightFirstCandidate + 1, '-');
            //      pindex = pindexPrev;
            //      while (pindex && pindex->nHeight >= nHeightFirstCandidate)
            //      {
            //          // '=' indicates proof-of-stake blocks not selected
            //          if (pindex->IsProofOfStake())
            //              strSelectionMap.replace(pindex->nHeight - nHeightFirstCandidate, 1, "=");
            //          pindex = pindex->pprev;
            //      }

            //      BOOST_FOREACH(const PAIRTYPE(uint256, const CBlockIndex*)& item, mapSelectedBlocks)
            //      {
            //          // 'S' indicates selected proof-of-stake blocks
            //          // 'W' indicates selected proof-of-work blocks
            //          strSelectionMap.replace(item.second->nHeight - nHeightFirstCandidate, 1, item.second->IsProofOfStake()? "S" : "W");
            //      }

            //      LogPrintf("ComputeNextStakeModifier: selection height [%d, %d] map %s\n", nHeightFirstCandidate, pindexPrev->nHeight, strSelectionMap);
            //  }

            //LogPrint("stakemodifier", "ComputeNextStakeModifier: new modifier=0x%016x time=%s\n", nStakeModifierNew, DateTimeStrFormat(pindexPrev->GetBlockTime()));

            nStakeModifier          = nStakeModifierNew;
            fGeneratedStakeModifier = true;
            return(true);
        }
示例#27
0
		public static MnemonicReference Create(ChainBase chain, Transaction transaction, Block block, int txOutIndex)
		{
			return Create(chain, transaction, block.Filter(transaction.GetHash()), txOutIndex);
		}
示例#28
0
		public ChainedBlock FindFork(ChainBase chain)
		{
			if(chain == null)
				throw new ArgumentNullException("chain");
			return FindFork(chain.ToEnumerable(true).Select(o => o.HashBlock));
		}