Exemple #1
0
        private TxMempoolEntry[] SetupTxMempool(ChainIndexer chainIndexer, ConsensusOptions newOptions, Money txFee, params Transaction[] transactions)
        {
            uint txTime     = Utils.DateTimeToUnixTime(chainIndexer.Tip.Header.BlockTime.AddSeconds(25));
            var  lockPoints = new LockPoints()
            {
                Height        = 4,
                MaxInputBlock = chainIndexer.GetHeader(4),
                Time          = chainIndexer.GetHeader(4).Header.Time
            };

            var resultingTransactionEntries = new List <TxMempoolEntry>();
            var indexedTransactionSet       = new TxMempool.IndexedTransactionSet();

            foreach (Transaction transaction in transactions)
            {
                var txPoolEntry = new TxMempoolEntry(transaction, txFee, txTime, 1, 4, new Money(400000000), false, 2, lockPoints, newOptions);
                indexedTransactionSet.Add(txPoolEntry);
                resultingTransactionEntries.Add(txPoolEntry);
            }

            this.txMempool.Setup(t => t.MapTx)
            .Returns(indexedTransactionSet);

            return(resultingTransactionEntries.ToArray());
        }
        public async Task BatchIsSavedAfterSizeThresholdReachedAsync()
        {
            Block block     = Block.Load(Encoders.Hex.DecodeData(this.testBlockHex), KnownNetworks.StratisMain.Consensus.ConsensusFactory);
            int   blockSize = block.GetSerializedSize();

            this.chainState.ConsensusTip = null;

            int count = 5 * 1024 * 1024 / blockSize + 2;

            ChainIndexer longChainIndexer = this.CreateChain(count);

            this.repositoryTipHashAndHeight = new HashHeightPair(longChainIndexer.Genesis.HashBlock, 0);

            var blockStoreFlushCondition = new BlockStoreQueueFlushCondition(this.chainState, this.initialBlockDownloadState.Object);

            this.blockStoreQueue = new BlockStoreQueue(longChainIndexer, this.chainState, blockStoreFlushCondition, this.storeSettings,
                                                       this.blockRepositoryMock.Object, this.loggerFactory, new Mock <INodeStats>().Object, this.asyncProvider);

            this.blockStoreQueue.Initialize();
            this.chainState.ConsensusTip = longChainIndexer.Tip;

            // Send all the blocks to the block store except for the last one because that will trigger batch saving because of reaching the tip.
            for (int i = 1; i < count; i++)
            {
                ChainedHeader header = longChainIndexer.GetHeader(i);

                this.blockStoreQueue.AddToPending(new ChainedHeaderBlock(block, header));
            }

            await WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

            Assert.Equal(longChainIndexer.GetHeader(count - 1), this.chainState.BlockStoreTip);
            Assert.Equal(1, this.repositorySavesCount);
        }
        public void CreateNewBlock_WithScript_DoesNotValidateTemplateUsingRuleContext()
        {
            var newOptions = new PosConsensusOptions();

            this.ExecuteWithConsensusOptions(newOptions, () =>
            {
                ChainIndexer chainIndexer = GenerateChainWithHeight(5, this.stratisTest, this.key);
                this.SetupRulesEngine(chainIndexer);
                this.dateTimeProvider.Setup(d => d.GetAdjustedTimeAsUnixTimestamp()).Returns(new DateTime(2017, 1, 7, 0, 0, 1, DateTimeKind.Utc).ToUnixTimestamp());
                this.consensusManager.Setup(c => c.Tip).Returns(chainIndexer.GetHeader(5));

                this.stakeValidator.Setup(s => s.GetNextTargetRequired(this.stakeChain.Object, chainIndexer.Tip, this.stratisTest.Consensus, true))
                .Returns(new Target(new uint256(1123123123)))
                .Verifiable();

                Transaction transaction = CreateTransaction(this.stratisTest, this.key, 5, new Money(400 * 1000 * 1000), new Key(), new uint256(124124));
                var txFee = new Money(1000);

                SetupTxMempool(chainIndexer, newOptions, txFee, transaction);

                var posBlockAssembler = new PosBlockDefinition(this.consensusManager.Object, this.dateTimeProvider.Object, this.LoggerFactory.Object, this.mempool.Object, new MempoolSchedulerLock(), this.minerSettings, this.stratisTest, this.stakeChain.Object, this.stakeValidator.Object, new NodeDeployments(this.Network, chainIndexer));

                BlockTemplate blockTemplate = posBlockAssembler.Build(chainIndexer.Tip, this.key.ScriptPubKey);

                this.consensusManager.Verify(c => c.ConsensusRules.PartialValidationAsync(It.IsAny <ChainedHeader>(), It.IsAny <Block>()), Times.Exactly(0));
                Assert.Null(this.callbackRuleContext);
                this.stakeValidator.Verify();
            });
        }
Exemple #4
0
        /// <summary>Calculates if BIP30 should be enforced for given block.</summary>
        public static bool EnforceBIP30ForBlock(ChainedHeader nextBlock, IConsensus chainparams, ChainIndexer chainIndexer)
        {
            // Do not allow blocks that contain transactions which 'overwrite' older transactions,
            // unless those are already completely spent.
            // If such overwrites are allowed, coinbases and transactions depending upon those
            // can be duplicated to remove the ability to spend the first instance -- even after
            // being sent to another address.
            // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information.
            // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool
            // already refuses previously-known transaction ids entirely.
            // This rule was originally applied to all blocks with a timestamp after March 15, 2012, 0:00 UTC.
            // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the
            // two in the chain that violate it. This prevents exploiting the issue against nodes during their
            // initial block download.
            bool enforceBIP30 = (nextBlock.HashBlock == null) || // Enforce on CreateNewBlock invocations which don't have a hash.
                                !((nextBlock.Height == 91842 && nextBlock.HashBlock == new uint256("00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
                                  (nextBlock.Height == 91880 && nextBlock.HashBlock == new uint256("00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));

            // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting
            // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs.  But by the
            // time BIP34 activated, in each of the existing pairs the duplicate coinbase had overwritten the first
            // before the first had been spent.  Since those coinbases are sufficiently buried its no longer possible to create further
            // duplicate transactions descending from the known pairs either.
            // If we're on the known chain at height greater than where BIP34 activated, we can save the db accesses needed for the BIP30 check.
            ChainedHeader bip34HeightChainedHeader = chainIndexer.GetHeader(chainparams.BuriedDeployments[BuriedDeployments.BIP34]);

            // Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond.
            enforceBIP30 = enforceBIP30 && ((bip34HeightChainedHeader == null) || !(bip34HeightChainedHeader.HashBlock == chainparams.BIP34Hash));

            return(enforceBIP30);
        }
        /// <summary>
        ///     Gets the height of the first block created at or after this date.
        /// </summary>
        /// <param name="chainIndexer">The chain of blocks.</param>
        /// <param name="date">The date.</param>
        /// <returns>The height of the first block created after the date.</returns>
        public static int GetHeightAtTime(this ChainIndexer chainIndexer, DateTime date)
        {
            var blockSyncStart = 0;
            var upperLimit     = chainIndexer.Tip.Height;
            var lowerLimit     = 0;
            var found          = false;

            while (!found)
            {
                var check            = lowerLimit + (upperLimit - lowerLimit) / 2;
                var blockTimeAtCheck = chainIndexer.GetHeader(check).Header.BlockTime.DateTime;

                if (blockTimeAtCheck > date)
                {
                    upperLimit = check;
                }
                else if (blockTimeAtCheck < date)
                {
                    lowerLimit = check;
                }
                else
                {
                    return(check);
                }

                if (upperLimit - lowerLimit <= 1)
                {
                    blockSyncStart = upperLimit;
                    found          = true;
                }
            }

            return(blockSyncStart);
        }
        public void ProcessBlock_NewBlock_BlockNotOnBestChain_ReOrgWalletManagerUsingBlockStoreCache()
        {
            (ChainIndexer LeftChain, ChainIndexer RightChain, List <Block> LeftForkBlocks, List <Block> RightForkBlocks)result = WalletTestsHelpers.GenerateForkedChainAndBlocksWithHeight(5, new StraxMain(), 2);

            // Left side chain containing the 'old' fork.
            ChainIndexer leftChainIndexer = result.LeftChain;

            // Right side chain containing the 'new' fork. Work on this.
            this.SetupMockObjects(result.RightChain);

            // Setup blockstore to return blocks on the chain.
            var blockDict = result.LeftForkBlocks.Concat(result.RightForkBlocks).Distinct().ToDictionary(b => b.GetHash(), b => b);

            this.blockStore.Setup(b => b.GetBlocks(It.IsAny <List <uint256> >()))
            .Returns((List <uint256> blockHashes) => blockHashes.Select(h => blockDict[h]).ToList());

            // Set 4th block of the old chain as tip. 2 ahead of the fork thus not being on the right chain.
            this.walletManager.Object.RewindWallet(this.walletName, leftChainIndexer.GetHeader(result.LeftForkBlocks[3].Header.GetHash()));

            // Rewind identifies height 2 as the last common block instead.
            Assert.Equal(2, this.walletTip.Height);

            // Sync will start at block 3 and end at block 5 which is the last block on the "right" chain.
            this.walletSyncManager.OrchestrateWalletSync();

            this.walletRepository.Verify(r => r.ProcessBlocks(
                                             It.Is <IEnumerable <(ChainedHeader header, Block block)> >(c => string.Join(",", c.Select(b => b.header.Height)) == "3,4,5"),
                                             It.IsAny <string>()));
        }
Exemple #7
0
        private ChainedHeader AddBlock(ChainIndexer chainIndexer)
        {
            BlockHeader header = this.network.Consensus.ConsensusFactory.CreateBlockHeader();

            header.Nonce         = RandomUtils.GetUInt32();
            header.HashPrevBlock = chainIndexer.Tip.HashBlock;
            chainIndexer.SetTip(header);
            return(chainIndexer.GetHeader(header.GetHash()));
        }
        public static bool TrySetTip(this ChainIndexer chainIndexer, BlockHeader header, out ChainedHeader chainedHeader)
        {
            if (header == null)
            {
                throw new ArgumentNullException("header");
            }

            chainedHeader = null;
            ChainedHeader prev = chainIndexer.GetHeader(header.HashPrevBlock);

            if (prev == null)
            {
                return(false);
            }

            chainedHeader = new ChainedHeader(header, header.GetHash(), chainIndexer.GetHeader(header.HashPrevBlock));
            chainIndexer.SetTip(chainedHeader);
            return(true);
        }
Exemple #9
0
        public void CanCalculateDifficulty()
        {
            var main = new ChainIndexer(this.network).Load(this.LoadMainChain());

            // The state of the line separators may be affected by copy operations - so do an environment independent line split...
            string[] histories = File.ReadAllText(TestDataLocations.GetFileFromDataFolder("targethistory.csv")).Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string history in histories)
            {
                int height         = int.Parse(history.Split(',')[0]);
                var expectedTarget = new Target(new BouncyCastle.Math.BigInteger(history.Split(',')[1], 10));

                BlockHeader block = main.GetHeader(height).Header;

                Assert.Equal(expectedTarget, block.Bits);
                Target target = main.GetHeader(height).GetWorkRequired(network);
                Assert.Equal(expectedTarget, target);
            }
        }
        public DeploymentFlags(ChainedHeader nextBlock, ThresholdState[] prevBlockStates, IConsensus chainparams,
                               ChainIndexer chainIndexer)
        {
            this.EnforceBIP30 = EnforceBIP30ForBlock(nextBlock);

            // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting
            // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs.  But by the
            // time BIP34 activated, in each of the existing pairs the duplicate coinbase had overwritten the first
            // before the first had been spent.  Since those coinbases are sufficiently buried its no longer possible to create further
            // duplicate transactions descending from the known pairs either.
            // If we're on the known chain at height greater than where BIP34 activated, we can save the db accesses needed for the BIP30 check.
            var bip34HeightChainedHeader =
                chainIndexer.GetHeader(chainparams.BuriedDeployments[BuriedDeployments.BIP34]);

            // Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond.
            this.EnforceBIP30 = this.EnforceBIP30 && (bip34HeightChainedHeader == null ||
                                                      !(bip34HeightChainedHeader.HashBlock == chainparams.BIP34Hash));

            // BIP16 didn't become active until Apr 1 2012.
            var nBIP16SwitchTime       = Utils.UnixTimeToDateTime(1333238400);
            var fStrictPayToScriptHash = nextBlock.Header.BlockTime >= nBIP16SwitchTime;

            this.ScriptFlags = fStrictPayToScriptHash ? ScriptVerify.P2SH : ScriptVerify.None;

            // Start enforcing the DERSIG (BIP66) rule.
            if (nextBlock.Height >= chainparams.BuriedDeployments[BuriedDeployments.BIP66])
            {
                this.ScriptFlags |= ScriptVerify.DerSig;
            }

            // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4
            // blocks, when 75% of the network has upgraded.
            if (nextBlock.Height >= chainparams.BuriedDeployments[BuriedDeployments.BIP65])
            {
                this.ScriptFlags |= ScriptVerify.CheckLockTimeVerify;
            }

            // Set the relevant flags for active BIP9 deployments.
            for (var deployment = 0; deployment < prevBlockStates.Length; deployment++)
            {
                if (prevBlockStates[deployment] == ThresholdState.Active)
                {
                    var flags = chainIndexer.Network.Consensus.BIP9Deployments.GetFlags(deployment);

                    this.ScriptFlags   |= flags.ScriptFlags;
                    this.LockTimeFlags |= flags.LockTimeFlags;
                }
            }

            // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
            if (nextBlock.Height >= chainparams.BuriedDeployments[BuriedDeployments.BIP34])
            {
                this.EnforceBIP34 = true;
            }
        }
        public static void WriteTo(this ChainIndexer chainIndexer, BitcoinStream stream)
        {
            stream.ConsensusFactory = chainIndexer.Network.Consensus.ConsensusFactory;

            for (int i = 0; i < chainIndexer.Tip.Height + 1; i++)
            {
                ChainedHeader block = chainIndexer.GetHeader(i);
                stream.ReadWrite(block.HashBlock.AsBitcoinSerializable());
                stream.ReadWrite(block.Header);
            }
        }
Exemple #12
0
        public void ConstructProvenHeaderPayload_Consecutive_Headers()
        {
            var provenHeaderChain = BuildProvenHeaderChain(10);

            var chain = new ChainIndexer(this.Network, provenHeaderChain);

            var consensusManager = new Mock <IConsensusManager>();

            consensusManager.Setup(c => c.Tip).Returns(provenHeaderChain);

            var behavior = new ProvenHeadersConsensusManagerBehavior(chain, this.initialBlockDownloadState, consensusManager.Object, this.peerBanning, this.extendedLoggerFactory, this.Network, this.chainState, this.checkpoints, this.provenBlockHeaderStore, this.connectionManagerSettings);

            var hashes = new List <uint256>();

            for (int i = 1; i < 5; i++)
            {
                var chainedHeaderToAdd = chain.GetHeader(i);
                hashes.Add(chainedHeaderToAdd.HashBlock);
            }
            hashes.Reverse();

            var blockLocator = new BlockLocator {
                Blocks = hashes
            };

            var peerMock = CreatePeerMock();

            behavior.Attach(peerMock.Object);

            var incomingMessage = new IncomingMessage
            {
                Message = new Message(new PayloadProvider().DiscoverPayloads())
                {
                    Magic   = this.Network.Magic,
                    Payload = new GetProvenHeadersPayload(blockLocator),
                }
            };

            var provenBlockHeadersToVerifyAgainst = new List <ProvenBlockHeader>();

            for (int i = 5; i <= provenHeaderChain.Height; i++)
            {
                provenBlockHeadersToVerifyAgainst.Add((ProvenBlockHeader)provenHeaderChain.GetAncestor(i).Header);
            }

            //Trigger the event handler
            peerMock.Object.MessageReceived.ExecuteCallbacksAsync(peerMock.Object, incomingMessage).GetAwaiter().GetResult();

            // Check that the headers we sent is the correct headers.
            var payload = new ProvenHeadersPayload(provenBlockHeadersToVerifyAgainst.ToArray());

            peerMock.Verify(p => p.SendMessageAsync(It.Is <ProvenHeadersPayload>(pl => VerifyHeaders(pl.Headers, provenBlockHeadersToVerifyAgainst)), default(CancellationToken)));
        }
        internal ChainedHeader GetTransactionBlock(uint256 trxid, IFullNode fullNode, ChainIndexer chain)
        {
            Guard.NotNull(fullNode, nameof(fullNode));

            ChainedHeader block = null;
            uint256 blockid = this.blockStore?.GetBlockIdByTransactionId(trxid);
            if (blockid != null)
            {
                block = chain?.GetHeader(blockid);
            }
            return block;
        }
Exemple #14
0
 public PosBlockModel(Block block, ChainIndexer chain)
 {
     Hash              = block.GetHash().ToString();
     Size              = block.ToBytes().Length;
     Version           = block.Header.Version;
     Bits              = block.Header.Bits.ToCompact().ToString("x8");
     Time              = block.Header.BlockTime;
     Nonce             = block.Header.Nonce;
     PreviousBlockHash = block.Header.HashPrevBlock.ToString();
     MerkleRoot        = block.Header.HashMerkleRoot.ToString();
     Difficulty        = block.Header.Bits.Difficulty;
     Transactions      = block.Transactions.Select(trx => new TransactionVerboseModel(trx, chain.Network)).ToArray();
     Height            = chain.GetHeader(block.GetHash()).Height;
 }
Exemple #15
0
        public void CanBuildConcurrentChain()
        {
            var cchain = new ChainIndexer(this.network);
            var chain  = new ChainIndexer(this.network);

            ChainedHeader b0 = cchain.Tip;

            Assert.Equal(cchain.Tip, chain.Tip);

            ChainedHeader b1 = this.AddBlock(chain);
            ChainedHeader b2 = this.AddBlock(chain);

            this.AddBlock(chain);
            this.AddBlock(chain);
            ChainedHeader b5 = this.AddBlock(chain);

            Assert.Equal(cchain.SetTip(chain.Tip), b0);
            Assert.Equal(cchain.Tip, chain.Tip);

            Assert.Equal(cchain.GetHeader(5), chain.Tip);
            Assert.Equal(cchain.GetHeader(b5.HashBlock), chain.Tip);

            Assert.Equal(cchain.SetTip(b1), b1);
            Assert.Null(cchain.GetHeader(b5.HashBlock));
            Assert.Null(cchain.GetHeader(b2.HashBlock));

            Assert.Equal(cchain.SetTip(b5), b1);
            Assert.Equal(cchain.GetHeader(b5.HashBlock), chain.Tip);

            chain.SetTip(b2);
            this.AddBlock(chain);
            this.AddBlock(chain);
            ChainedHeader b5b = this.AddBlock(chain);
            ChainedHeader b6b = this.AddBlock(chain);

            Assert.Equal(cchain.SetTip(b6b), b2);

            Assert.Null(cchain.GetHeader(b5.HashBlock));
            Assert.Equal(cchain.GetHeader(b2.HashBlock), b2);
            Assert.Equal(cchain.GetHeader(6), b6b);
            Assert.Equal(cchain.GetHeader(5), b5b);
        }
        public async Task ReorgedBlocksAreNotSavedAsync()
        {
            this.repositoryTipHashAndHeight = new HashHeightPair(this.chainIndexer.Genesis.HashBlock, 0);

            var blockStoreFlushConditionMock = new Mock <IBlockStoreQueueFlushCondition>();

            blockStoreFlushConditionMock.Setup(s => s.ShouldFlush).Returns(false);
            this.blockStoreQueue = new BlockStoreQueue(this.chainIndexer, this.chainState, blockStoreFlushConditionMock.Object, this.storeSettings,
                                                       this.blockRepositoryMock.Object, this.loggerFactory, new Mock <INodeStats>().Object, this.asyncProvider);

            this.blockStoreQueue.Initialize();

            int reorgedChainLenght = 3;
            int realChainLenght    = 6;

            // First present a short chain.
            ChainIndexer alternativeChainIndexer = CreateChain(reorgedChainLenght);

            for (int i = 1; i < alternativeChainIndexer.Height; i++)
            {
                Block block = this.network.Consensus.ConsensusFactory.CreateBlock();
                block.GetSerializedSize();

                this.blockStoreQueue.AddToPending(new ChainedHeaderBlock(block, alternativeChainIndexer.GetHeader(i)));
            }

            // Present second chain which has more work and reorgs blocks from genesis.
            for (int i = 1; i < realChainLenght; i++)
            {
                Block block = this.network.Consensus.ConsensusFactory.CreateBlock();
                block.GetSerializedSize();

                this.blockStoreQueue.AddToPending(new ChainedHeaderBlock(block, this.chainIndexer.GetHeader(i)));
            }

            await this.WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

            Assert.Equal(this.chainState.BlockStoreTip, this.chainIndexer.Genesis);
            Assert.Equal(0, this.repositorySavesCount);

            // Dispose block store to trigger save.
            this.nodeLifetime.StopApplication();
            this.blockStoreQueue.Dispose();

            // Make sure that blocks only from 2nd chain were saved.
            Assert.Equal(this.chainIndexer.GetHeader(realChainLenght - 1), this.chainState.BlockStoreTip);
            Assert.Equal(1, this.repositorySavesCount);
            Assert.Equal(realChainLenght - 1, this.repositoryTotalBlocksSaved);
        }
        /// <summary>
        /// Retrieves a transaction block given a valid hash.
        /// This function is used by other methods in this class and not explicitly by RPC/API.
        /// </summary>
        /// <param name="trxid">A valid uint256 hash</param>
        /// <param name="fullNode">The full node. Used to access <see cref="IBlockStore"/>.</param>
        /// <param name="chain">The full node's chain. Used to get <see cref="ChainedHeader"/> block.</param>
        /// <returns>A <see cref="ChainedHeader"/> for the given transaction hash. Returns <c>null</c> if fails.</returns>
        /// <exception cref="ArgumentNullException">Thrown if fullnode is not provided.</exception>
        internal static async Task <ChainedHeader> GetTransactionBlockAsync(uint256 trxid, IFullNode fullNode, ChainIndexer chain)
        {
            Guard.NotNull(fullNode, nameof(fullNode));

            ChainedHeader block      = null;
            var           blockStore = fullNode.NodeFeature <IBlockStore>();
            uint256       blockid    = blockStore != null?blockStore.GetBlockIdByTransactionId(trxid) : null;

            if (blockid != null)
            {
                block = chain?.GetHeader(blockid);
            }

            return(block);
        }
Exemple #18
0
        /// <summary>
        ///     Retrieves a transaction block given a valid hash.
        ///     This function is used by other methods in this class and not explicitly by RPC/API.
        /// </summary>
        /// <param name="trxid">A valid uint256 hash</param>
        /// <param name="fullNode">The full node. Used to access <see cref="IBlockStore" />.</param>
        /// <param name="chain">The full node's chain. Used to get <see cref="ChainedHeader" /> block.</param>
        /// <returns>A <see cref="ChainedHeader" /> for the given transaction hash. Returns <c>null</c> if fails.</returns>
        /// <exception cref="ArgumentNullException">Thrown if fullnode is not provided.</exception>
        internal ChainedHeader GetTransactionBlock(uint256 trxid, IFullNode fullNode, ChainIndexer chain)
        {
            Guard.NotNull(fullNode, nameof(fullNode));

            ChainedHeader block      = null;
            var           blockStore = fullNode.NodeFeature <IBlockStore>();
            var           blockid    = blockStore?.GetBlockIdByTransactionId(trxid);

            if (blockid != null)
            {
                block = chain?.GetHeader(blockid);
            }

            return(block);
        }
        public static byte[] ToBytes(this ChainIndexer chainIndexer)
        {
            using (var ms = new MemoryStream())
            {
                var stream = new BitcoinStream(ms, true, chainIndexer.Network.Consensus.ConsensusFactory);

                for (int i = 0; i < chainIndexer.Tip.Height + 1; i++)
                {
                    ChainedHeader block = chainIndexer.GetHeader(i);
                    stream.ReadWrite(block.HashBlock.AsBitcoinSerializable());
                    stream.ReadWrite(block.Header);
                }

                return(ms.ToArray());
            }
        }
        public void GetBlockCount_ReturnsHeightFromChainState()
        {
            var          logger       = new Mock <ILoggerFactory>();
            var          store        = new Mock <IBlockStore>();
            var          chainState   = new Mock <IChainState>();
            ChainIndexer chainIndexer = WalletTestsHelpers.GenerateChainWithHeight(3, KnownNetworks.StratisTest);

            logger.Setup(l => l.CreateLogger(It.IsAny <string>())).Returns(Mock.Of <ILogger>);

            chainState.Setup(c => c.ConsensusTip)
            .Returns(chainIndexer.GetHeader(2));

            var controller = new BlockStoreController(KnownNetworks.StratisTest, logger.Object, store.Object, chainState.Object, chainIndexer);

            var json   = (JsonResult)controller.GetBlockCount();
            int result = int.Parse(json.Value.ToString());

            Assert.Equal(2, result);
        }
        public void ProcessBlock_NewBlock_BlockNotOnBestChain_ReOrgWalletManagerUsingBlockStoreCache()
        {
            (ChainIndexer LeftChain, ChainIndexer RightChain, List <Block> LeftForkBlocks, List <Block> RightForkBlocks)result = WalletTestsHelpers.GenerateForkedChainAndBlocksWithHeight(5, KnownNetworks.StratisMain, 2);
            // left side chain containing the 'old' fork.
            ChainIndexer leftChainIndexer = result.LeftChain;

            // right side chain containing the 'new' fork. Work on this.
            this.chainIndexer = result.RightChain;
            var walletSyncManager = new WalletSyncManagerOverride(this.LoggerFactory.Object, this.walletManager.Object, this.chainIndexer, KnownNetworks.StratisMain,
                                                                  this.blockStore.Object, this.storeSettings, this.signals, this.asyncProvider);

            // setup blockstore to return blocks on the chain.
            this.blockStore.Setup(b => b.GetBlock(It.IsAny <uint256>()))
            .Returns((uint256 hashblock) =>
            {
                return(result.LeftForkBlocks.Union(result.RightForkBlocks).Single(b => b.GetHash() == hashblock));
            });

            // set 4th block of the old chain as tip. 2 ahead of the fork thus not being on the right chain.
            walletSyncManager.SetWalletTip(leftChainIndexer.GetHeader(result.LeftForkBlocks[3].Header.GetHash()));
            //process 5th block from the right side of the fork in the list does not have same prevhash as which is loaded.
            Block blockToProcess = result.RightForkBlocks[4];

            blockToProcess.SetPrivatePropertyValue("BlockSize", 1L);

            walletSyncManager.ProcessBlock(blockToProcess);

            this.AssertTipBlockHash(walletSyncManager, 5);

            // walletmanager removes all blocks up to the fork.
            this.walletManager.Verify(w => w.RemoveBlocks(ExpectChainedBlock(this.chainIndexer.GetHeader(2))));

            //verify manager processes each missing block until caught up.
            // height 3
            this.walletManager.Verify(w => w.ProcessBlock(ExpectBlock(result.RightForkBlocks[2]), ExpectChainedBlock(this.chainIndexer.GetHeader(3))));
            // height 4
            this.walletManager.Verify(w => w.ProcessBlock(ExpectBlock(result.RightForkBlocks[3]), ExpectChainedBlock(this.chainIndexer.GetHeader(4))));
            // height 5
            this.walletManager.Verify(w => w.ProcessBlock(ExpectBlock(result.RightForkBlocks[4]), ExpectChainedBlock(this.chainIndexer.GetHeader(5))), Times.Exactly(2));
        }
Exemple #22
0
        public void CanLoadAndSaveConcurrentChain()
        {
            var cchain = new ChainIndexer(this.network);
            var chain  = new ChainIndexer(this.network);

            this.AddBlock(chain);
            this.AddBlock(chain);
            this.AddBlock(chain);

            cchain.SetTip(chain.Tip);

            byte[] bytes = cchain.ToBytes();
            cchain = new ChainIndexer(this.network);
            cchain.Load(bytes);

            Assert.Equal(cchain.Tip, chain.Tip);
            Assert.NotNull(cchain.GetHeader(0));

            cchain = new ChainIndexer(this.networkTest);
            cchain.Load(cchain.ToBytes());
            Assert.NotNull(cchain.GetHeader(0));
        }
Exemple #23
0
        public void AddTransactions_TransactionAlreadyInInblock_DoesNotAddTransactionToBlock()
        {
            var newOptions = new ConsensusOptions();

            this.ExecuteWithConsensusOptions(newOptions, () =>
            {
                ChainIndexer chainIndexer = GenerateChainWithHeight(5, this.testNet, this.key);
                this.consensusManager.Setup(c => c.Tip)
                .Returns(chainIndexer.GetHeader(5));
                Transaction transaction = CreateTransaction(this.testNet, this.key, 5, new Money(400 * 1000 * 1000), new Key(), new uint256(124124));
                var txFee = new Money(1000);
                TxMempoolEntry[] entries = SetupTxMempool(chainIndexer, newOptions, txFee, transaction);

                var blockDefinition = new PowTestBlockDefinition(this.consensusManager.Object, this.dateTimeProvider.Object, this.LoggerFactory.Object, this.txMempool.Object, new MempoolSchedulerLock(), this.minerSettings, this.testNet, this.consensusRules.Object, new NodeDeployments(this.testNet, chainIndexer));
                blockDefinition.AddInBlockTxEntries(entries);

                (Block Block, int Selected, int Updated)result = blockDefinition.AddTransactions();

                Assert.Empty(result.Block.Transactions);
                Assert.Equal(0, result.Selected);
                Assert.Equal(0, result.Updated);
            });
        }
Exemple #24
0
        public void AddTransactions_WithoutTransactionsInMempool_DoesNotAddEntriesToBlock()
        {
            var newOptions = new ConsensusOptions();

            this.ExecuteWithConsensusOptions(newOptions, () =>
            {
                ChainIndexer chainIndexer = GenerateChainWithHeight(5, this.testNet, new Key());
                this.consensusManager.Setup(c => c.Tip)
                .Returns(chainIndexer.GetHeader(5));
                var indexedTransactionSet = new TxMempool.IndexedTransactionSet();
                this.txMempool.Setup(t => t.MapTx)
                .Returns(indexedTransactionSet);

                var blockDefinition = new PowTestBlockDefinition(this.consensusManager.Object, this.dateTimeProvider.Object, this.LoggerFactory.Object, this.txMempool.Object,
                                                                 new MempoolSchedulerLock(), this.minerSettings, this.testNet, this.consensusRules.Object, new NodeDeployments(this.testNet, chainIndexer));

                (Block Block, int Selected, int Updated)result = blockDefinition.AddTransactions();

                Assert.Empty(result.Block.Transactions);
                Assert.Equal(0, result.Selected);
                Assert.Equal(0, result.Updated);
            });
        }
        public void AddTransactions_WithoutTransactionsInMempool_DoesNotAddEntriesToBlock()
        {
            var newOptions = new PosConsensusOptions();

            this.ExecuteWithConsensusOptions(newOptions, () =>
            {
                ChainIndexer chainIndexer = GenerateChainWithHeight(5, this.stratisTest, new Key());
                this.consensusManager.Setup(c => c.Tip)
                .Returns(chainIndexer.GetHeader(5));
                var indexedTransactionSet = new TxMempool.IndexedTransactionSet();
                this.mempool.Setup(t => t.MapTx)
                .Returns(indexedTransactionSet);

                var posBlockAssembler = new PosTestBlockAssembler(this.consensusManager.Object, this.stratisTest, new MempoolSchedulerLock(), this.mempool.Object, this.minerSettings,
                                                                  this.dateTimeProvider.Object, this.stakeChain.Object, this.stakeValidator.Object, this.LoggerFactory.Object);

                (Block Block, int Selected, int Updated)result = posBlockAssembler.AddTransactions();

                Assert.Empty(result.Block.Transactions);
                Assert.Equal(0, result.Selected);
                Assert.Equal(0, result.Updated);
            });
        }
        public void AddTransactions_TransactionNotInblock_AddsTransactionToBlock()
        {
            var newOptions = new PosConsensusOptions();

            this.ExecuteWithConsensusOptions(newOptions, () =>
            {
                ChainIndexer chainIndexer = GenerateChainWithHeight(5, this.stratisTest, this.key);
                this.consensusManager.Setup(c => c.Tip)
                .Returns(chainIndexer.GetHeader(5));

                Mock <IConsensusRuleEngine> consensusRuleEngine = new Mock <IConsensusRuleEngine>();
                consensusRuleEngine.Setup(s => s.GetRule <PosFutureDriftRule>()).Returns(new PosFutureDriftRule());

                this.consensusManager.Setup(c => c.ConsensusRules)
                .Returns(consensusRuleEngine.Object);

                Transaction transaction = CreateTransaction(this.stratisTest, this.key, 5, new Money(400 * 1000 * 1000), new Key(), new uint256(124124));

                this.dateTimeProvider.Setup(s => s.GetAdjustedTimeAsUnixTimestamp()).Returns(chainIndexer.Tip.Header.Time);

                var txFee = new Money(1000);
                SetupTxMempool(chainIndexer, newOptions, txFee, transaction);

                var posBlockAssembler = new PosTestBlockAssembler(this.consensusManager.Object, this.stratisTest, new MempoolSchedulerLock(), this.mempool.Object, this.minerSettings, this.dateTimeProvider.Object, this.stakeChain.Object, this.stakeValidator.Object, this.LoggerFactory.Object, new NodeDeployments(this.Network, chainIndexer));

                posBlockAssembler.CreateCoinBase(new ChainedHeader(this.stratisTest.GetGenesis().Header, this.stratisTest.GetGenesis().Header.GetHash(), 0), new KeyId().ScriptPubKey);

                (Block Block, int Selected, int Updated)result = posBlockAssembler.AddTransactions();

                Assert.NotEmpty(result.Block.Transactions);

                Assert.Equal(transaction.ToHex(), result.Block.Transactions[1].ToHex());
                Assert.Equal(1, result.Selected);
                Assert.Equal(0, result.Updated);
            });
        }
        public void ComputeBlockVersion_UsingChainTipAndConsensus_Bip9DeploymentActive_UpdatesHeightAndVersion()
        {
            ConsensusOptions options          = this.stratisTest.Consensus.Options;
            int minerConfirmationWindow       = this.stratisTest.Consensus.MinerConfirmationWindow;
            int ruleChangeActivationThreshold = this.stratisTest.Consensus.RuleChangeActivationThreshold;

            try
            {
                var newOptions = new PosConsensusOptions();
                this.stratisTest.Consensus.Options            = newOptions;
                this.stratisTest.Consensus.BIP9Deployments[0] = new BIP9DeploymentsParameters(19,
                                                                                              new DateTimeOffset(new DateTime(2016, 1, 1, 0, 0, 0, DateTimeKind.Utc)),
                                                                                              new DateTimeOffset(new DateTime(2018, 1, 1, 0, 0, 0, DateTimeKind.Utc)));

                this.stratisTest.Consensus.MinerConfirmationWindow       = 2;
                this.stratisTest.Consensus.RuleChangeActivationThreshold = 2;

                ChainIndexer chainIndexer = GenerateChainWithHeightAndActivatedBip9(5, this.stratisTest, new Key(), this.stratisTest.Consensus.BIP9Deployments[0]);
                this.SetupRulesEngine(chainIndexer);

                var posBlockAssembler = new PosTestBlockAssembler(this.consensusManager.Object, this.stratisTest, new MempoolSchedulerLock(), this.mempool.Object, this.minerSettings, this.dateTimeProvider.Object, this.stakeChain.Object, this.stakeValidator.Object, this.LoggerFactory.Object);

                (int Height, int Version)result = posBlockAssembler.ComputeBlockVersion(chainIndexer.GetHeader(4));

                Assert.Equal(5, result.Height);
                int expectedVersion = (int)(ThresholdConditionCache.VersionbitsTopBits | (((uint)1) << 19));
                Assert.Equal(expectedVersion, result.Version);
                Assert.NotEqual((int)ThresholdConditionCache.VersionbitsTopBits, result.Version);
            }
            finally
            {
                // This is a static in the global context so be careful updating it. I'm resetting it after being done testing so I don't influence other tests.
                this.stratisTest.Consensus.Options                       = options;
                this.stratisTest.Consensus.BIP9Deployments[0]            = null;
                this.stratisTest.Consensus.MinerConfirmationWindow       = minerConfirmationWindow;
                this.stratisTest.Consensus.RuleChangeActivationThreshold = ruleChangeActivationThreshold;
            }
        }
Exemple #28
0
        /// <summary>
        /// Creates the test chain with some default blocks and txs.
        /// </summary>
        /// <param name="network">Network to create the chain on.</param>
        /// <param name="scriptPubKey">Public key to create blocks/txs with.</param>
        /// <returns>Context object representing the test chain.</returns>
        public static async Task <ITestChainContext> CreateAsync(Network network, Script scriptPubKey, string dataDir)
        {
            var nodeSettings = new NodeSettings(network, args: new string[] { $"-datadir={dataDir}" });

            ILoggerFactory    loggerFactory    = nodeSettings.LoggerFactory;
            IDateTimeProvider dateTimeProvider = DateTimeProvider.Default;

            network.Consensus.Options = new ConsensusOptions();
            new FullNodeBuilderConsensusExtension.PowConsensusRulesRegistration().RegisterRules(network.Consensus);

            // Dont check PoW of a header in this test.
            network.Consensus.HeaderValidationRules.RemoveAll(x => x.GetType() == typeof(CheckDifficultyPowRule));

            var consensusSettings = new ConsensusSettings(nodeSettings);
            var chain             = new ChainIndexer(network);
            var inMemoryCoinView  = new InMemoryCoinView(chain.Tip.HashBlock);

            var chainState  = new ChainState();
            var deployments = new NodeDeployments(network, chain);
            ConsensusRuleEngine consensusRules = new PowConsensusRuleEngine(network, loggerFactory, dateTimeProvider, chain, deployments, consensusSettings, new Checkpoints(),
                                                                            inMemoryCoinView, chainState, new InvalidBlockHashStore(dateTimeProvider), new NodeStats(dateTimeProvider)).Register();

            ConsensusManager consensus = ConsensusManagerHelper.CreateConsensusManager(network, dataDir, chainState);

            var genesis = new ChainedHeader(network.GetGenesis().Header, network.GenesisHash, 0);

            chainState.BlockStoreTip = genesis;
            await consensus.InitializeAsync(genesis).ConfigureAwait(false);

            var blockPolicyEstimator = new BlockPolicyEstimator(new MempoolSettings(nodeSettings), loggerFactory, nodeSettings);
            var mempool     = new TxMempool(dateTimeProvider, blockPolicyEstimator, loggerFactory, nodeSettings);
            var mempoolLock = new MempoolSchedulerLock();

            var minerSettings = new MinerSettings(nodeSettings);

            // Simple block creation, nothing special yet:
            var           blockDefinition = new PowBlockDefinition(consensus, dateTimeProvider, loggerFactory, mempool, mempoolLock, minerSettings, network, consensusRules);
            BlockTemplate newBlock        = blockDefinition.Build(chain.Tip, scriptPubKey);

            await consensus.BlockMinedAsync(newBlock.Block);

            List <BlockInfo> blockinfo = CreateBlockInfoList();

            // We can't make transactions until we have inputs therefore, load 100 blocks.
            var blocks = new List <Block>();
            var srcTxs = new List <Transaction>();

            for (int i = 0; i < blockinfo.Count; ++i)
            {
                Block currentBlock = Block.Load(newBlock.Block.ToBytes(network.Consensus.ConsensusFactory), network.Consensus.ConsensusFactory);
                currentBlock.Header.HashPrevBlock = chain.Tip.HashBlock;
                currentBlock.Header.Version       = 1;
                currentBlock.Header.Time          = Utils.DateTimeToUnixTime(chain.Tip.GetMedianTimePast()) + 1;

                Transaction txCoinbase = network.CreateTransaction(currentBlock.Transactions[0].ToBytes());
                txCoinbase.Inputs.Clear();
                txCoinbase.Version = 1;
                txCoinbase.AddInput(new TxIn(new Script(new[] { Op.GetPushOp(blockinfo[i].extraNonce), Op.GetPushOp(chain.Height) })));
                // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
                txCoinbase.AddOutput(new TxOut(Money.Zero, new Script()));
                currentBlock.Transactions[0] = txCoinbase;

                if (srcTxs.Count < 4)
                {
                    srcTxs.Add(currentBlock.Transactions[0]);
                }

                currentBlock.UpdateMerkleRoot();

                currentBlock.Header.Nonce = blockinfo[i].nonce;

                chain.SetTip(currentBlock.Header);
            }

            // Just to make sure we can still make simple blocks
            blockDefinition = new PowBlockDefinition(consensus, dateTimeProvider, loggerFactory, mempool, mempoolLock, minerSettings, network, consensusRules);
            blockDefinition.Build(chain.Tip, scriptPubKey);

            var mempoolValidator = new MempoolValidator(mempool, mempoolLock, dateTimeProvider, new MempoolSettings(nodeSettings), chain, inMemoryCoinView, loggerFactory, nodeSettings, consensusRules);

            var outputs = new List <UnspentOutputs>();

            foreach (Transaction tx in srcTxs)
            {
                var output = new UnspentOutputs(0, tx);

                outputs.Add(output);
            }

            inMemoryCoinView.SaveChanges(outputs, new List <TxOut[]>(), chain.GetHeader(0).HashBlock, chain.GetHeader(1).HashBlock, chain.GetHeader(0).Height);

            return(new TestChainContext {
                MempoolValidator = mempoolValidator, SrcTxs = srcTxs
            });
        }
Exemple #29
0
        public void ComputeBlockVersion_UsingChainTipAndConsensus_Bip9DeploymentActive_UpdatesHeightAndVersion()
        {
            ConsensusOptions options    = this.testNet.Consensus.Options;
            int minerConfirmationWindow = this.testNet.Consensus.MinerConfirmationWindow;

            try
            {
                var newOptions = new ConsensusOptions();
                this.testNet.Consensus.Options            = newOptions;
                this.testNet.Consensus.BIP9Deployments[0] = new BIP9DeploymentsParameters("Test",
                                                                                          19, new DateTimeOffset(new DateTime(2016, 1, 1, 0, 0, 0, DateTimeKind.Utc)),
                                                                                          new DateTimeOffset(new DateTime(2018, 1, 1, 0, 0, 0, DateTimeKind.Utc)),
                                                                                          2);

                // As we are effectively using TestNet the other deployments need to be disabled
                this.testNet.Consensus.BIP9Deployments[BitcoinBIP9Deployments.CSV]    = null;
                this.testNet.Consensus.BIP9Deployments[BitcoinBIP9Deployments.Segwit] = null;

                this.testNet.Consensus.MinerConfirmationWindow = 2;

                ChainIndexer chainIndexer = GenerateChainWithHeightAndActivatedBip9(5, this.testNet, new Key(), this.testNet.Consensus.BIP9Deployments[0]);
                this.SetupRulesEngine(chainIndexer);

                var blockDefinition = new PowTestBlockDefinition(this.consensusManager.Object, this.dateTimeProvider.Object, this.LoggerFactory.Object, this.txMempool.Object, new MempoolSchedulerLock(), this.minerSettings, this.testNet, this.consensusRules.Object, new NodeDeployments(this.testNet, chainIndexer));

                (int Height, int Version)result = blockDefinition.ComputeBlockVersion(chainIndexer.GetHeader(4));

                Assert.Equal(5, result.Height);
                int expectedVersion = (int)(ThresholdConditionCache.VersionbitsTopBits | (((uint)1) << 19));
                Assert.Equal(expectedVersion, result.Version);
                Assert.NotEqual((int)ThresholdConditionCache.VersionbitsTopBits, result.Version);
            }
            finally
            {
                // This is a static in the global context so be careful updating it. I'm resetting it after being done testing so I don't influence other tests.
                this.testNet.Consensus.Options                 = options;
                this.testNet.Consensus.BIP9Deployments[0]      = null;
                this.testNet.Consensus.MinerConfirmationWindow = minerConfirmationWindow;
            }
        }
Exemple #30
0
        public void ComputeBlockVersion_UsingChainTipAndConsensus_NoBip9DeploymentActive_UpdatesHeightAndVersion()
        {
            this.ExecuteWithConsensusOptions(new ConsensusOptions(), () =>
            {
                ChainIndexer chainIndexer = GenerateChainWithHeight(5, this.testNet, new Key());
                this.SetupRulesEngine(chainIndexer);

                var blockDefinition = new PowTestBlockDefinition(this.consensusManager.Object, this.dateTimeProvider.Object, this.LoggerFactory.Object, this.txMempool.Object, new MempoolSchedulerLock(), this.minerSettings, this.testNet, this.consensusRules.Object, new NodeDeployments(this.testNet, chainIndexer));

                (int Height, int Version)result = blockDefinition.ComputeBlockVersion(chainIndexer.GetHeader(4));

                Assert.Equal(5, result.Height);
                Assert.Equal((int)ThresholdConditionCache.VersionbitsTopBits, result.Version);
            });
        }