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(); }); }
/// <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>())); }
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); }
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); } }
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; }
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; }
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); }
/// <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)); }
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)); }
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); }); }
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; } }
/// <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 }); }
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; } }
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); }); }