//[Trait("UnitTest", "UnitTest")] public void CanCreateBrainAddress() { var repo = new NoSqlBlockRepository(); var chain = new ConcurrentChain(); Block b = new Block(); b.Transactions.Add(new Transaction()); b.Transactions.Add(new Transaction() { Outputs = { new TxOut(), new TxOut(Money.Zero,BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe")) } }); b.UpdateMerkleRoot(); repo.PutAsync(b).Wait(); chain.SetTip(b.Header); MnemonicReference address = MnemonicReference.CreateAsync(chain, repo, 0, 1, 1).Result; MnemonicReference address2 = MnemonicReference.ParseAsync(chain, repo, Wordlist.English, address.ToString(Wordlist.English)).Result; Assert.Equal(address.ToString(), address2.ToString()); chain = new ConcurrentChain(Network.Main); var block = Network.Main.GetGenesis(); var mnemo = MnemonicReference.Create(chain, block.Transactions[0], block, 0); }
public void CanLoadAndSaveConcurrentChain() { ConcurrentChain cchain = new ConcurrentChain(); ConcurrentChain chain = new ConcurrentChain(Network.Main); AddBlock(chain); AddBlock(chain); AddBlock(chain); cchain.SetTip(chain); var bytes = cchain.ToBytes(); cchain = new ConcurrentChain(); cchain.Load(bytes); Assert.Equal(cchain.Tip, chain.Tip); Assert.NotNull(cchain.GetBlock(0)); cchain = new ConcurrentChain(Network.TestNet); cchain.Load(cchain.ToBytes()); Assert.NotNull(cchain.GetBlock(0)); }
protected void AddBlocksToChain(ConcurrentChain chain, int blockAmount) { uint nonce = RandomUtils.GetUInt32(); uint256 prevBlockHash = chain.Tip.HashBlock; (this.ruleContext as UtxoRuleContext).UnspentOutputSet = new UnspentOutputSet(); (this.ruleContext as UtxoRuleContext).UnspentOutputSet.SetCoins(new UnspentOutputs[0]); for (int i = 0; i < blockAmount; i++) { Block block = chain.Network.Consensus.ConsensusFactory.CreateBlock(); Transaction transaction = chain.Network.CreateTransaction(); block.AddTransaction(transaction); block.UpdateMerkleRoot(); block.Header.BlockTime = new DateTimeOffset(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddDays(i)); block.Header.HashPrevBlock = prevBlockHash; block.Header.Nonce = nonce; chain.SetTip(block.Header); prevBlockHash = block.GetHash(); (this.ruleContext as UtxoRuleContext).UnspentOutputSet.Update(transaction, i); this.lastAddedTransaction = transaction; } }
private static ConcurrentChain GenerateChainWithHeight(int blockAmount, Network network, Key key) { var chain = new ConcurrentChain(network); var nonce = RandomUtils.GetUInt32(); var prevBlockHash = chain.Genesis.HashBlock; for (var i = 0; i < blockAmount; i++) { var block = network.Consensus.ConsensusFactory.CreateBlock(); Transaction coinStake = CreateCoinStakeTransaction(network, key, chain.Height + 1, new uint256((ulong)12312312 + (ulong)i)); block.AddTransaction(coinStake); block.UpdateMerkleRoot(); block.Header.BlockTime = new DateTimeOffset(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddDays(i)); block.Header.HashPrevBlock = prevBlockHash; block.Header.Nonce = nonce; chain.SetTip(block.Header); prevBlockHash = block.GetHash(); } return(chain); }
public void CanLoadAndSaveConcurrentChain() { var cchain = new ConcurrentChain(); var chain = new ConcurrentChain(Network.Main); AddBlock(chain); AddBlock(chain); AddBlock(chain); cchain.SetTip(chain); var bytes = cchain.ToBytes(); cchain = new ConcurrentChain(); cchain.Load(bytes, Consensus.Main.ConsensusFactory); Assert.Equal(cchain.Tip, chain.Tip); Assert.NotNull(cchain.GetBlock(0)); cchain = new ConcurrentChain(Network.TestNet); cchain.Load(cchain.ToBytes(), Consensus.Main.ConsensusFactory); Assert.NotNull(cchain.GetBlock(0)); }
public static ConcurrentChain GenerateChainWithBlockTimeAndHeight(int blockAmount, Network network, int incrementSeconds, uint nbits) { var chain = new ConcurrentChain(network); var nonce = RandomUtils.GetUInt32(); var prevBlockHash = chain.Genesis.HashBlock; var blockTime = Utils.UnixTimeToDateTime(chain.Genesis.Header.Time).UtcDateTime; for (var i = 0; i < blockAmount; i++) { var block = network.Consensus.ConsensusFactory.CreateBlock(); block.AddTransaction(new Transaction()); block.UpdateMerkleRoot(); block.Header.BlockTime = new DateTimeOffset(blockTime); blockTime = blockTime.AddSeconds(incrementSeconds); block.Header.HashPrevBlock = prevBlockHash; block.Header.Nonce = nonce; block.Header.Bits = new Target(nbits); chain.SetTip(block.Header); prevBlockHash = block.GetHash(); } return(chain); }
public void CanLoadAndSaveConcurrentChain() { ConcurrentChain cchain = new ConcurrentChain(); ConcurrentChain chain = new ConcurrentChain(Network.PurpleMain); AddBlock(chain); AddBlock(chain); AddBlock(chain); cchain.SetTip(chain); var bytes = cchain.ToBytes(); cchain = new ConcurrentChain(); cchain.Load(bytes); Assert.Equal(cchain.Tip, chain.Tip); Assert.NotNull(cchain.GetBlock(0)); cchain = new ConcurrentChain(Network.PurpleTest); cchain.Load(cchain.ToBytes()); Assert.NotNull(cchain.GetBlock(0)); }
public void Mine(int blockCount) { List <Block> blocks = new List <Block>(); DateTimeOffset now = DateTimeOffset.UtcNow; for (int i = 0; i < blockCount; i++) { uint nonce = 0; Block block = new Block(); block.Header.HashPrevBlock = _Chain.Tip.HashBlock; block.Header.Bits = block.Header.GetWorkRequired(_Network, _Chain.Tip); block.Header.UpdateTime(now, _Network, _Chain.Tip); var coinbase = new Transaction(); coinbase.AddInput(TxIn.CreateCoinbase(_Chain.Height + 1)); coinbase.AddOutput(new TxOut(_Network.GetReward(_Chain.Height + 1), MinerScriptPubKey)); block.AddTransaction(coinbase); foreach (var tx in _Transactions) { block.AddTransaction(tx); } block.UpdateMerkleRoot(); while (!block.CheckProofOfWork()) { block.Header.Nonce = ++nonce; } block.Header.CacheHashes(); blocks.Add(block); _Transactions.Clear(); _Chain.SetTip(block.Header); } foreach (var b in blocks) { _Blocks.Add(b.GetHash(), b); } }
public void CanEnumerateAfterChainedBlock() { var chain = new ConcurrentChain(this.network); this.AppendBlock(chain); ChainedHeader a = this.AppendBlock(chain); ChainedHeader b = this.AppendBlock(chain); ChainedHeader c = this.AppendBlock(chain); Assert.True(chain.EnumerateAfter(a).SequenceEqual(new[] { b, c })); ChainedHeader d = this.AppendBlock(chain); IEnumerator <ChainedHeader> enumerator = chain.EnumerateAfter(b).GetEnumerator(); enumerator.MoveNext(); Assert.True(enumerator.Current == c); chain.SetTip(b); ChainedHeader cc = this.AppendBlock(chain); ChainedHeader dd = this.AppendBlock(chain); Assert.False(enumerator.MoveNext()); }
public BestChainSelectorTest() { this.chainedHeaders = new List <ChainedHeader>(); var chain = new ConcurrentChain(Network.StratisMain); for (int i = 0; i < 20; ++i) { var header = new BlockHeader() { Nonce = RandomUtils.GetUInt32(), HashPrevBlock = chain.Tip.HashBlock, Bits = Target.Difficulty1 }; var chainedHeader = new ChainedHeader(header, header.GetHash(), chain.Tip); chain.SetTip(chainedHeader); this.chainedHeaders.Add(chainedHeader); } // Let block #5 be the consensus tip. this.chainState = new Mock <IChainState>().SetupProperty(x => x.ConsensusTip, this.chainedHeaders[5]); }
public void CanEnumerateAfterChainedBlock() { ConcurrentChain chain = new ConcurrentChain(Network.Main); AppendBlock(chain); var a = AppendBlock(chain); var b = AppendBlock(chain); var c = AppendBlock(chain); Assert.True(chain.EnumerateAfter(a).SequenceEqual(new[] { b, c })); var d = AppendBlock(chain); var enumerator = chain.EnumerateAfter(b).GetEnumerator(); enumerator.MoveNext(); Assert.True(enumerator.Current == c); chain.SetTip(b); var cc = AppendBlock(chain); var dd = AppendBlock(chain); Assert.False(enumerator.MoveNext()); }
/// <summary>Creates the and attaches a new <see cref="ConsensusManagerBehavior"/>.</summary> /// <param name="consensusTip">Consensus tip.</param> /// <param name="cache">List of cached headers with which behavior is initialized.</param> /// <param name="bestReceivedTip">Behavior's expected tip's initial value.</param> /// <param name="peerState">Peer connection state returned by the <see cref="INetworkPeer.State"/>.</param> /// <param name="connectNewHeadersMethod">Method which is invoked when behavior calls <see cref="IConsensusManager.HeadersPresented"/>.</param> /// <returns></returns> public ConsensusManagerBehavior CreateAndAttachBehavior(ChainedHeader consensusTip, List <BlockHeader> cache = null, ChainedHeader bestReceivedTip = null, NetworkPeerState peerState = NetworkPeerState.HandShaked, Func <List <BlockHeader>, bool, ConnectNewHeadersResult> connectNewHeadersMethod = null) { // Chain var chain = new ConcurrentChain(KnownNetworks.StratisMain); chain.SetTip(consensusTip); // Ibd var ibdState = new Mock <IInitialBlockDownloadState>(); ibdState.Setup(x => x.IsInitialBlockDownload()).Returns(() => this.IsIBD); // Consensus manager var cmMock = new Mock <IConsensusManager>(); cmMock.Setup(x => x.HeadersPresented(It.IsAny <INetworkPeer>(), It.IsAny <List <BlockHeader> >(), It.IsAny <bool>())) .Returns((INetworkPeer p, List <BlockHeader> presentedHeaders, bool triggerDownload) => { this.HeadersPresentedCalledTimes++; return(connectNewHeadersMethod?.Invoke(presentedHeaders, triggerDownload)); }); cmMock.Setup(x => x.Tip).Returns(consensusTip); this.testPeerBanning = new TestPeerBanning(); var connectionManagerMock = new Mock <IConnectionManager>(); connectionManagerMock.SetupGet(x => x.ConnectionSettings).Returns(new ConnectionManagerSettings(new NodeSettings(KnownNetworks.StratisMain))); var cmBehavior = new ConsensusManagerBehavior(chain, ibdState.Object, cmMock.Object, this.testPeerBanning, this.loggerFactory); // Peer and behavior this.PeerMock = this.CreatePeerMock(); cmBehavior.Attach(this.PeerMock.Object); this.PeerMock.Setup(x => x.Behavior <ConsensusManagerBehavior>()).Returns(() => cmBehavior); this.PeerMock.Setup(x => x.State).Returns(peerState); if (bestReceivedTip != null) { cmBehavior.SetPrivatePropertyValue(nameof(cmBehavior.BestReceivedTip), bestReceivedTip); cmBehavior.SetPrivatePropertyValue(nameof(cmBehavior.BestSentHeader), bestReceivedTip); } if (cache != null) { cmBehavior.SetPrivateVariableValue("cachedHeaders", cache); } this.GetHeadersPayloadSentTimes = 0; this.HeadersPayloadsSent = new List <HeadersPayload>(); this.GetHeadersPayloadsSent = new List <GetHeadersPayload>(); this.PeerMock.Setup(x => x.SendMessageAsync(It.IsAny <Payload>(), It.IsAny <CancellationToken>())).Returns((Payload payload, CancellationToken token) => { if (payload is GetHeadersPayload getHeadersPayload) { this.GetHeadersPayloadSentTimes++; this.GetHeadersPayloadsSent.Add(getHeadersPayload); } if (payload is HeadersPayload headersPayload) { this.HeadersPayloadsSent.Add(headersPayload); } return(Task.CompletedTask); }); this.PeerMock.Setup(x => x.SendMessage(It.IsAny <Payload>())).Callback((Payload payload) => { if (payload is GetHeadersPayload getHeadersPayload) { this.GetHeadersPayloadSentTimes++; this.GetHeadersPayloadsSent.Add(getHeadersPayload); } if (payload is HeadersPayload headersPayload) { this.HeadersPayloadsSent.Add(headersPayload); } }); return(cmBehavior); }
public void CanFindFork() { var chain1 = new ConcurrentChain(this.network); // Create the main chain with a commonChainSize blocks before the fork. int commonChainSize = 150000; for (int i = 0; i < commonChainSize; i++) { this.AppendBlock(chain1); } ChainedHeader fork = this.AppendBlock(chain1); // Add some blocks from the fork point to the tip. int chain1AppendixSize = 100; for (int i = 0; i < chain1AppendixSize; i++) { this.AppendBlock(chain1); } // Tip of the chain1. ChainedHeader chain1Tip = chain1.Tip; { // Test scenario 1: // chain2 is empty, so the fork point is supposed to be the Genesis. var chain2 = new ConcurrentChain(this.network); this.AssertFork(chain1, chain2, chain1.Genesis); } { // Test scenario 2: // chain2 is a chain on another network, null expected. var chain2 = new ConcurrentChain(this.networkTest); this.AssertFork(chain1, chain2, null); } { // Test scenario 3: // chain2 is a subset of chain1 and stops at the fork point "c", fork point expected. var chain2 = new ConcurrentChain(this.network); chain2.SetTip(fork); this.AssertFork(chain1, chain2, fork); } { // Test scenario 4: // chain2 is a forked chain (at the fork point "c") that has other blocks on top of it, fork point expected. var chain2 = new ConcurrentChain(this.network); chain2.SetTip(fork); var chain2ForkDepth = 200; for (int i = 0; i < chain2ForkDepth; i++) { this.AppendBlock(chain2); } this.AssertFork(chain1, chain2, fork); } { // Test scenario 5: // chain2 is at the same tip of chain1, no fork happened, tip point expected. var chain2 = new ConcurrentChain(this.network); chain2.SetTip(chain1Tip); this.AssertFork(chain1, chain2, chain1Tip); } }
static void Main(string[] args) { decimal subbuCoin1 = 0; decimal subbuCoin2 = 0; decimal sendAmount = 0; int blockCount = 0; int option = 0; RandomUtils.Random = new UnsecureRandom(); List <Transaction> transactionList = new List <Transaction>(); DateTimeOffset current = DateTimeOffset.UtcNow; ConcurrentChain chain = new ConcurrentChain(Network.Main); Key subbuPrivateKey = new Key(); Key swethaPrivateKey = new Key(); Key adityaPrivateKey = new Key(); Key kavyaPrivateKey = new Key(); BitcoinSecret subbu = subbuPrivateKey.GetBitcoinSecret(Network.Main); BitcoinSecret swetha = swethaPrivateKey.GetBitcoinSecret(Network.Main); BitcoinSecret aditya = adityaPrivateKey.GetBitcoinSecret(Network.Main); BitcoinSecret kavya = kavyaPrivateKey.GetBitcoinSecret(Network.Main); Console.WriteLine("\n Enter first coin value:"); subbuCoin1 = Convert.ToDecimal(Console.ReadLine()); Console.WriteLine("\n Enter second coin value:"); subbuCoin2 = Convert.ToDecimal(Console.ReadLine()); decimal totalAmount = subbuCoin1 + subbuCoin2; Console.WriteLine("\n Total Coins Value: " + totalAmount); while (blockCount != 5) { while (option != 1) { Console.WriteLine("\n Enter Send amount:"); sendAmount = Convert.ToDecimal(Console.ReadLine()); Transaction subbuFunding = new Transaction() { Outputs = { new TxOut(subbuCoin1.ToString(), subbu.GetAddress()), new TxOut(subbuCoin2.ToString(), subbu.PubKey) } }; Coin[] subbuCoins = subbuFunding .Outputs .Select((o, i) => new Coin(new OutPoint(subbuFunding.GetHash(), i), o)) .ToArray(); var txBuilder = new TransactionBuilder(); var tx = txBuilder .AddCoins(subbuCoins) .AddKeys(subbu.PrivateKey) .Send(swetha.GetAddress(), sendAmount.ToString()) .SendFees("0.001") .SetChange(subbu.GetAddress()) .BuildTransaction(true); Console.WriteLine(tx); Console.ReadLine(); transactionList.Add(tx); Console.WriteLine("Press 1 for Mine block or 2 go to next transaction:"); option = int.Parse(Console.ReadLine()); } chain.SetTip(CreateBlock(current, blockCount, transactionList, chain)); blockCount++; option = 0; } }
public void CanPersistMainchain() { var main = new ConcurrentChain(LoadMainChain(), Consensus.Main.ConsensusFactory); var ms = new MemoryStream(); main.WriteTo(ms); ms.Position = 0; main.SetTip(main.Genesis); main.Load(ms); Assert.True(main.Tip.HasHeader); var original = main; foreach (var options in new[] { new ConcurrentChain.ChainSerializationFormat { SerializeBlockHeader = true, SerializePrecomputedBlockHash = true }, new ConcurrentChain.ChainSerializationFormat { SerializeBlockHeader = true, SerializePrecomputedBlockHash = false }, new ConcurrentChain.ChainSerializationFormat { SerializeBlockHeader = false, SerializePrecomputedBlockHash = true } }) { main = new ConcurrentChain(); main.SetTip(original.Tip); ms = new MemoryStream(); main.WriteTo(ms, options); ms.Position = 0; main.SetTip(main.Genesis); main.Load(ms, Consensus.Main.ConsensusFactory, options); Assert.Equal(options.SerializeBlockHeader, main.Tip.HasHeader); if (main.Tip.HasHeader) { Assert.True(main.Tip.TryGetHeader(out var unused)); } else { Assert.False(main.Tip.TryGetHeader(out var unused)); Assert.Throws <InvalidOperationException>(() => main.Tip.Header); } Assert.Equal(original.Tip.HashBlock, main.Tip.HashBlock); } Assert.Throws <InvalidOperationException>(() => { main.WriteTo(new MemoryStream(), new ConcurrentChain.ChainSerializationFormat { SerializeBlockHeader = false, SerializePrecomputedBlockHash = false }); }); }
public void CanForkBackward() { ConcurrentChain chain = new ConcurrentChain(Network.Main); AppendBlock(chain); AppendBlock(chain); var fork = AppendBlock(chain); //Test single block back fork var last = AppendBlock(chain); Assert.Equal(4, chain.Height); Assert.Equal(4, last.Height); Assert.Equal(last.HashBlock, chain.Tip.HashBlock); Assert.Equal(fork.HashBlock, chain.SetTip(fork).HashBlock); Assert.Equal(3, chain.Height); Assert.Equal(3, fork.Height); Assert.Equal(fork.HashBlock, chain.Tip.HashBlock); Assert.Null(chain.GetBlock(last.HashBlock)); Assert.NotNull(chain.GetBlock(fork.HashBlock)); //Test 3 blocks back fork var b1 = AppendBlock(chain); var b2 = AppendBlock(chain); last = AppendBlock(chain); Assert.Equal(6, chain.Height); Assert.Equal(6, last.Height); Assert.Equal(last.HashBlock, chain.Tip.HashBlock); Assert.Equal(fork.HashBlock, chain.SetTip(fork).HashBlock); Assert.Equal(3, chain.Height); Assert.Equal(3, fork.Height); Assert.Equal(fork.HashBlock, chain.Tip.HashBlock); Assert.Null(chain.GetBlock(last.HashBlock)); Assert.Null(chain.GetBlock(b1.HashBlock)); Assert.Null(chain.GetBlock(b2.HashBlock)); chain.SetTip(last); Assert.Equal(6, chain.Height); Assert.Equal(6, last.Height); Assert.Equal(last.HashBlock, chain.Tip.HashBlock); }
public void CanGetMedianBlock() { ConcurrentChain chain = new ConcurrentChain(Network.Main); DateTimeOffset now = DateTimeOffset.UtcNow; chain.SetTip(CreateBlock(now, 0, chain)); chain.SetTip(CreateBlock(now, -1, chain)); chain.SetTip(CreateBlock(now, 1, chain)); Assert.Equal(CreateBlock(now, 0).Header.BlockTime, chain.Tip.GetMedianTimePast()); // x -1 0 1 chain.SetTip(CreateBlock(now, 2, chain)); Assert.Equal(CreateBlock(now, 0).Header.BlockTime, chain.Tip.GetMedianTimePast()); // x -1 0 1 2 chain.SetTip(CreateBlock(now, 3, chain)); Assert.Equal(CreateBlock(now, 1).Header.BlockTime, chain.Tip.GetMedianTimePast()); // x -1 0 1 2 3 chain.SetTip(CreateBlock(now, 4, chain)); chain.SetTip(CreateBlock(now, 5, chain)); chain.SetTip(CreateBlock(now, 6, chain)); chain.SetTip(CreateBlock(now, 7, chain)); chain.SetTip(CreateBlock(now, 8, chain)); Assert.Equal(CreateBlock(now, 3).Header.BlockTime, chain.Tip.GetMedianTimePast()); // x -1 0 1 2 3 4 5 6 7 8 chain.SetTip(CreateBlock(now, 9, chain)); Assert.Equal(CreateBlock(now, 4).Header.BlockTime, chain.Tip.GetMedianTimePast()); // x -1 0 1 2 3 4 5 6 7 8 9 chain.SetTip(CreateBlock(now, 10, chain)); Assert.Equal(CreateBlock(now, 5).Header.BlockTime, chain.Tip.GetMedianTimePast()); // x -1 0 1 2 3 4 5 6 7 8 9 10 }
private ChainedBlock AddBlock(ConcurrentChain chain) { BlockHeader header = new BlockHeader(); header.Nonce = RandomUtils.GetUInt32(); header.HashPrevBlock = chain.Tip.HashBlock; chain.SetTip(header); return chain.GetBlock(header.GetHash()); }
/// <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) { NodeSettings nodeSettings = new NodeSettings(network.Name, network).LoadArguments(new string[] { $"-datadir={dataDir}" }); if (dataDir != null) { nodeSettings.DataDir = dataDir; } var loggerFactory = new ExtendedLoggerFactory(); IDateTimeProvider dateTimeProvider = DateTimeProvider.Default; network.Consensus.Options = new PowConsensusOptions(); ConsensusSettings consensusSettings = new ConsensusSettings(nodeSettings, loggerFactory); PowConsensusValidator consensusValidator = new PowConsensusValidator(network, new Checkpoints(), dateTimeProvider, loggerFactory); ConcurrentChain chain = new ConcurrentChain(network); CachedCoinView cachedCoinView = new CachedCoinView(new InMemoryCoinView(chain.Tip.HashBlock), DateTimeProvider.Default, loggerFactory); NetworkPeerFactory networkPeerFactory = new NetworkPeerFactory(network, dateTimeProvider, loggerFactory); var peerAddressManager = new PeerAddressManager(nodeSettings.DataFolder, loggerFactory); var peerDiscovery = new PeerDiscovery(new AsyncLoopFactory(loggerFactory), loggerFactory, Network.PurpleMain, networkPeerFactory, new NodeLifetime(), nodeSettings, peerAddressManager); var connectionManager = new ConnectionManager(dateTimeProvider, loggerFactory, network, networkPeerFactory, nodeSettings, new NodeLifetime(), new NetworkPeerConnectionParameters(), peerAddressManager, new IPeerConnector[] { }, peerDiscovery); LookaheadBlockPuller blockPuller = new LookaheadBlockPuller(chain, connectionManager, new LoggerFactory()); PeerBanning peerBanning = new PeerBanning(connectionManager, loggerFactory, dateTimeProvider, nodeSettings); NodeDeployments deployments = new NodeDeployments(network, chain); ConsensusRules consensusRules = new ConsensusRules(network, loggerFactory, dateTimeProvider, chain, deployments, consensusSettings, new Checkpoints()).Register(new FullNodeBuilderConsensusExtension.CoreConsensusRules()); ConsensusLoop consensus = new ConsensusLoop(new AsyncLoopFactory(loggerFactory), consensusValidator, new NodeLifetime(), chain, cachedCoinView, blockPuller, deployments, loggerFactory, new ChainState(new InvalidBlockHashStore(dateTimeProvider)), connectionManager, dateTimeProvider, new Signals.Signals(), consensusSettings, nodeSettings, peerBanning, consensusRules); await consensus.StartAsync(); BlockPolicyEstimator blockPolicyEstimator = new BlockPolicyEstimator(new MempoolSettings(nodeSettings), loggerFactory, nodeSettings); TxMempool mempool = new TxMempool(dateTimeProvider, blockPolicyEstimator, loggerFactory, nodeSettings); MempoolSchedulerLock mempoolLock = new MempoolSchedulerLock(); // Simple block creation, nothing special yet: PowBlockAssembler blockAssembler = CreatePowBlockAssembler(network, consensus, chain, mempoolLock, mempool, dateTimeProvider, loggerFactory); BlockTemplate newBlock = blockAssembler.CreateNewBlock(scriptPubKey); chain.SetTip(newBlock.Block.Header); await consensus.ValidateAndExecuteBlockAsync(new RuleContext(new BlockValidationContext { Block = newBlock.Block }, network.Consensus, consensus.Tip) { CheckPow = false, CheckMerkleRoot = false }); List <BlockInfo> blockinfo = CreateBlockInfoList(); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) int baseheight = 0; List <Block> blocks = new List <Block>(); List <Transaction> srcTxs = new List <Transaction>(); for (int i = 0; i < blockinfo.Count; ++i) { Block currentBlock = newBlock.Block.Clone(); // pointer for convenience currentBlock.Header.HashPrevBlock = chain.Tip.HashBlock; currentBlock.Header.Version = 1; currentBlock.Header.Time = Utils.DateTimeToUnixTime(chain.Tip.GetMedianTimePast()) + 1; Transaction txCoinbase = currentBlock.Transactions[0].Clone(); 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 == 0) { baseheight = chain.Height; } if (srcTxs.Count < 4) { srcTxs.Add(currentBlock.Transactions[0]); } currentBlock.UpdateMerkleRoot(); currentBlock.Header.Nonce = blockinfo[i].nonce; chain.SetTip(currentBlock.Header); await consensus.ValidateAndExecuteBlockAsync(new RuleContext(new BlockValidationContext { Block = currentBlock }, network.Consensus, consensus.Tip) { CheckPow = false, CheckMerkleRoot = false }); blocks.Add(currentBlock); } // Just to make sure we can still make simple blocks blockAssembler = CreatePowBlockAssembler(network, consensus, chain, mempoolLock, mempool, dateTimeProvider, loggerFactory); newBlock = blockAssembler.CreateNewBlock(scriptPubKey); MempoolValidator mempoolValidator = new MempoolValidator(mempool, mempoolLock, consensusValidator, dateTimeProvider, new MempoolSettings(nodeSettings), chain, cachedCoinView, loggerFactory, nodeSettings); return(new TestChainContext { MempoolValidator = mempoolValidator, SrcTxs = srcTxs }); }
private ConcurrentChain CreateChain(BlockHeader genesis, int height) { var chain = new ConcurrentChain(genesis); for(int i = 0; i < height; i++) { var b = TestUtils.CreateFakeBlock(); b.Header.HashPrevBlock = chain.Tip.HashBlock; chain.SetTip(b.Header); } return chain; }
public void CanForkSidePartialChain() { var genesis = TestUtils.CreateFakeBlock(); ConcurrentChain side = new ConcurrentChain(genesis.Header); ConcurrentChain main = new ConcurrentChain(genesis.Header); AppendBlock(side, main); AppendBlock(side, main); var common = AppendBlock(side, main); var sideb = AppendBlock(side); var mainb1 = AppendBlock(main); var mainb2 = AppendBlock(main); var mainb3 = AppendBlock(main); Assert.Equal(common.HashBlock, side.SetTip(main.Tip).HashBlock); Assert.NotNull(side.GetBlock(mainb1.HashBlock)); Assert.NotNull(side.GetBlock(mainb2.HashBlock)); Assert.NotNull(side.GetBlock(mainb3.HashBlock)); Assert.NotNull(side.GetBlock(common.HashBlock)); Assert.Null(side.GetBlock(sideb.HashBlock)); Assert.Equal(common.HashBlock, side.SetTip(sideb).HashBlock); Assert.Null(side.GetBlock(mainb1.HashBlock)); Assert.Null(side.GetBlock(mainb2.HashBlock)); Assert.Null(side.GetBlock(mainb3.HashBlock)); Assert.NotNull(side.GetBlock(sideb.HashBlock)); }
public void CanForkSide() { ConcurrentChain side = new ConcurrentChain(Network.Main); ConcurrentChain main = new ConcurrentChain(Network.Main); AppendBlock(side, main); AppendBlock(side, main); var common = AppendBlock(side, main); var sideb = AppendBlock(side); var mainb1 = AppendBlock(main); var mainb2 = AppendBlock(main); var mainb3 = AppendBlock(main); Assert.Equal(common.HashBlock, side.SetTip(main.Tip).HashBlock); Assert.NotNull(side.GetBlock(mainb1.HashBlock)); Assert.NotNull(side.GetBlock(mainb2.HashBlock)); Assert.NotNull(side.GetBlock(mainb3.HashBlock)); Assert.NotNull(side.GetBlock(common.HashBlock)); Assert.Null(side.GetBlock(sideb.HashBlock)); Assert.Equal(common.HashBlock, side.SetTip(sideb).HashBlock); Assert.Null(side.GetBlock(mainb1.HashBlock)); Assert.Null(side.GetBlock(mainb2.HashBlock)); Assert.Null(side.GetBlock(mainb3.HashBlock)); Assert.NotNull(side.GetBlock(sideb.HashBlock)); }
public Block[] Generate(int blockCount, bool includeUnbroadcasted = true, bool broadcast = true) { var rpc = CreateRPCClient(); BitcoinSecret dest = GetFirstSecret(rpc); var bestBlock = rpc.GetBestBlockHash(); ConcurrentChain chain = null; List <Block> blocks = new List <Block>(); DateTimeOffset now = MockTime == null ? DateTimeOffset.UtcNow : MockTime.Value; #if !NOSOCKET using (var node = CreateNodeClient()) { node.VersionHandshake(); chain = bestBlock == node.Network.GenesisHash ? new ConcurrentChain(node.Network) : node.GetChain(); for (int i = 0; i < blockCount; i++) { uint nonce = 0; Block block = new Block(); block.Header.HashPrevBlock = chain.Tip.HashBlock; block.Header.Bits = block.Header.GetWorkRequired(rpc.Network, chain.Tip); block.Header.UpdateTime(now, rpc.Network, chain.Tip); var coinbase = new Transaction(); coinbase.AddInput(TxIn.CreateCoinbase(chain.Height + 1)); coinbase.AddOutput(new TxOut(rpc.Network.GetReward(chain.Height + 1), dest.GetAddress())); block.AddTransaction(coinbase); if (includeUnbroadcasted) { foreach (var tx in transactions.ToList()) { if (tx.Inputs.Any(input => _ToMalleate.Contains(input.PrevOut.Hash))) { transactions.Remove(tx); } } transactions = Reorder(transactions); block.Transactions.AddRange(transactions); for (int y = 0; y < block.Transactions.Count; y++) { if (_ToMalleate.Contains(block.Transactions[y].GetHash())) { block.Transactions[y] = DoMalleate(block.Transactions[y]); } } transactions.Clear(); _ToMalleate.Clear(); } block.UpdateMerkleRoot(); while (!block.CheckProofOfWork()) { block.Header.Nonce = ++nonce; } blocks.Add(block); chain.SetTip(block.Header); } if (broadcast) { BroadcastBlocks(blocks.ToArray(), node); } } return(blocks.ToArray()); #endif }
/// <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 ConcurrentChain(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); 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); } await inMemoryCoinView.SaveChangesAsync(outputs, new List <TxOut[]>(), chain.GetBlock(0).HashBlock, chain.GetBlock(1).HashBlock, chain.GetBlock(0).Height); return(new TestChainContext { MempoolValidator = mempoolValidator, SrcTxs = srcTxs }); }
public TestContext() { Logs.Configure(new LoggerFactory()); this.blockinfo = new List <Blockinfo>(); var lst = blockinfoarr.Cast <long>().ToList(); for (int i = 0; i < lst.Count; i += 2) { blockinfo.Add(new Blockinfo() { extranonce = (int)lst[i], nonce = (uint)lst[i + 1] }); } // Note that by default, these tests run with size accounting enabled. network = Network.Main; var hex = Encoders.Hex.DecodeData("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"); scriptPubKey = new Script(new[] { Op.GetPushOp(hex), OpcodeType.OP_CHECKSIG }); newBlock = new BlockTemplate(); entry = new TestMemPoolEntryHelper(); chain = new ConcurrentChain(network); network.Consensus.Options = new PowConsensusOptions(); cachedCoinView = new CachedCoinView(new InMemoryCoinView(chain.Tip.HashBlock)); consensus = new ConsensusLoop(new PowConsensusValidator(network), chain, cachedCoinView, new LookaheadBlockPuller(chain, new ConnectionManager(network, new NodeConnectionParameters(), new NodeSettings()))); consensus.Initialize(); entry.Fee(11); entry.Height(11); var date1 = new MemoryPoolTests.DateTimeProviderSet(); date1.time = DateTimeProvider.Default.GetTime(); date1.timeutc = DateTimeProvider.Default.GetUtcNow(); date = date1; mempool = new TxMempool(new FeeRate(0), new NodeSettings()); scheduler = new MempoolScheduler(); // Simple block creation, nothing special yet: newBlock = AssemblerForTest(this).CreateNewBlock(scriptPubKey); chain.SetTip(newBlock.Block.Header); consensus.AcceptBlock(new ContextInformation(new BlockResult { Block = newBlock.Block }, network.Consensus) { CheckPow = false, CheckMerkleRoot = false }); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) this.baseheight = 0; List <Block> blocks = new List <Block>(); txFirst = new List <Transaction>(); for (int i = 0; i < blockinfo.Count; ++i) { var pblock = newBlock.Block.Clone(); // pointer for convenience pblock.Header.HashPrevBlock = chain.Tip.HashBlock; pblock.Header.Version = 1; pblock.Header.Time = Utils.DateTimeToUnixTime(chain.Tip.GetMedianTimePast()) + 1; Transaction txCoinbase = pblock.Transactions[0].Clone(); 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())); pblock.Transactions[0] = txCoinbase; if (txFirst.Count == 0) { this.baseheight = chain.Height; } if (txFirst.Count < 4) { txFirst.Add(pblock.Transactions[0]); } pblock.UpdateMerkleRoot(); pblock.Header.Nonce = blockinfo[i].nonce; chain.SetTip(pblock.Header); consensus.AcceptBlock(new ContextInformation(new BlockResult { Block = pblock }, network.Consensus) { CheckPow = false, CheckMerkleRoot = false }); blocks.Add(pblock); } // Just to make sure we can still make simple blocks newBlock = AssemblerForTest(this).CreateNewBlock(scriptPubKey); Assert.NotNull(newBlock); }
private void CanVerifySequenceLockCore(Sequence[] sequences, int[] prevHeights, int currentHeight, DateTimeOffset first, bool expected, SequenceLock expectedLock) { ConcurrentChain chain = new ConcurrentChain(new BlockHeader() { BlockTime = first }); first = first + TimeSpan.FromMinutes(10); while(currentHeight != chain.Height) { chain.SetTip(new BlockHeader() { BlockTime = first, HashPrevBlock = chain.Tip.HashBlock }); first = first + TimeSpan.FromMinutes(10); } Transaction tx = new Transaction(); tx.Version = 2; for(int i = 0 ; i < sequences.Length ; i++) { TxIn input = new TxIn(); input.Sequence = sequences[i]; tx.Inputs.Add(input); } Assert.Equal(expected, tx.CheckSequenceLocks(prevHeights, chain.Tip)); var actualLock = tx.CalculateSequenceLocks(prevHeights, chain.Tip); Assert.Equal(expectedLock.MinTime, actualLock.MinTime); Assert.Equal(expectedLock.MinHeight, actualLock.MinHeight); }
public void CanEnumerateAfterChainedBlock() { ConcurrentChain chain = new ConcurrentChain(Network.Main); AppendBlock(chain); var a = AppendBlock(chain); var b = AppendBlock(chain); var c = AppendBlock(chain); Assert.True(chain.EnumerateAfter(a).SequenceEqual(new[] { b, c })); var d = AppendBlock(chain); var enumerator = chain.EnumerateAfter(b).GetEnumerator(); enumerator.MoveNext(); Assert.True(enumerator.Current == c); chain.SetTip(b); var cc = AppendBlock(chain); var dd = AppendBlock(chain); Assert.False(enumerator.MoveNext()); }
public void CanBuildConcurrentChain() { ConcurrentChain cchain = new ConcurrentChain(); ConcurrentChain chain = new ConcurrentChain(Network.Main); Assert.Null(cchain.SetTip(chain.Tip)); var b0 = cchain.Tip; Assert.Equal(cchain.Tip, chain.Tip); var b1 = AddBlock(chain); var b2 = AddBlock(chain); AddBlock(chain); AddBlock(chain); var b5 = AddBlock(chain); Assert.Equal(cchain.SetTip(chain.Tip), b0); Assert.Equal(cchain.Tip, chain.Tip); Assert.Equal(cchain.GetBlock(5), chain.Tip); Assert.Equal(cchain.GetBlock(b5.HashBlock), chain.Tip); Assert.Equal(cchain.SetTip(b1), b1); Assert.Equal(cchain.GetBlock(b5.HashBlock), null); Assert.Equal(cchain.GetBlock(b2.HashBlock), null); Assert.Equal(cchain.SetTip(b5), b1); Assert.Equal(cchain.GetBlock(b5.HashBlock), chain.Tip); chain.SetTip(b2); AddBlock(chain); AddBlock(chain); var b5b = AddBlock(chain); var b6b = AddBlock(chain); Assert.Equal(cchain.SetTip(b6b), b2); Assert.Equal(cchain.GetBlock(b5.HashBlock), null); Assert.Equal(cchain.GetBlock(b2.HashBlock), b2); Assert.Equal(cchain.GetBlock(6), b6b); Assert.Equal(cchain.GetBlock(5), b5b); }
/// <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 ITestChainContext Create(Network network, Script scriptPubKey) { NodeSettings nodeSettings = NodeSettings.Default(); LoggerFactory loggerFactory = new LoggerFactory(); IDateTimeProvider dateTimeProvider = DateTimeProvider.Default; network.Consensus.Options = new PowConsensusOptions(); PowConsensusValidator consensusValidator = new PowConsensusValidator(network); ConcurrentChain chain = new ConcurrentChain(network); CachedCoinView cachedCoinView = new CachedCoinView(new InMemoryCoinView(chain.Tip.HashBlock), loggerFactory); ConnectionManager connectionManager = new ConnectionManager(network, new NodeConnectionParameters(), nodeSettings, loggerFactory, new NodeLifetime()); LookaheadBlockPuller blockPuller = new LookaheadBlockPuller(chain, connectionManager, new LoggerFactory()); ConsensusLoop consensus = new ConsensusLoop(consensusValidator, chain, cachedCoinView, blockPuller, new NodeDeployments(network)); consensus.Initialize(); BlockPolicyEstimator blockPolicyEstimator = new BlockPolicyEstimator(new FeeRate(1000), nodeSettings, loggerFactory); TxMempool mempool = new TxMempool(new FeeRate(1000), dateTimeProvider, blockPolicyEstimator, loggerFactory); MempoolAsyncLock mempoolLock = new MempoolAsyncLock(); // Simple block creation, nothing special yet: PowBlockAssembler blockAssembler = CreatePowBlockAssembler(network, consensus, chain, mempoolLock, mempool, dateTimeProvider); BlockTemplate newBlock = blockAssembler.CreateNewBlock(scriptPubKey); chain.SetTip(newBlock.Block.Header); consensus.AcceptBlock(new ContextInformation(new BlockResult { Block = newBlock.Block }, network.Consensus) { CheckPow = false, CheckMerkleRoot = false }); List <BlockInfo> blockinfo = CreateBlockInfoList(); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) int baseheight = 0; List <Block> blocks = new List <Block>(); List <Transaction> srcTxs = new List <Transaction>(); for (int i = 0; i < blockinfo.Count; ++i) { Block currentBlock = newBlock.Block.Clone(); // pointer for convenience currentBlock.Header.HashPrevBlock = chain.Tip.HashBlock; currentBlock.Header.Version = 1; currentBlock.Header.Time = Utils.DateTimeToUnixTime(chain.Tip.GetMedianTimePast()) + 1; Transaction txCoinbase = currentBlock.Transactions[0].Clone(); 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 == 0) { baseheight = chain.Height; } if (srcTxs.Count < 4) { srcTxs.Add(currentBlock.Transactions[0]); } currentBlock.UpdateMerkleRoot(); currentBlock.Header.Nonce = blockinfo[i].nonce; chain.SetTip(currentBlock.Header); consensus.AcceptBlock(new ContextInformation(new BlockResult { Block = currentBlock }, network.Consensus) { CheckPow = false, CheckMerkleRoot = false }); blocks.Add(currentBlock); } // Just to make sure we can still make simple blocks blockAssembler = CreatePowBlockAssembler(network, consensus, chain, mempoolLock, mempool, dateTimeProvider); newBlock = blockAssembler.CreateNewBlock(scriptPubKey); MempoolValidator mempoolValidator = new MempoolValidator(mempool, mempoolLock, consensusValidator, dateTimeProvider, nodeSettings, chain, cachedCoinView, loggerFactory); return(new TestChainContext { MempoolValidator = mempoolValidator, SrcTxs = srcTxs }); }
/// <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(); network.Consensus.Rules = new FullNodeBuilderConsensusExtension.PowConsensusRulesRegistration().GetRules(); var consensusSettings = new ConsensusSettings(nodeSettings); var chain = new ConcurrentChain(network); InMemoryCoinView inMemoryCoinView = new InMemoryCoinView(chain.Tip.HashBlock); var cachedCoinView = new CachedCoinView(inMemoryCoinView, DateTimeProvider.Default, loggerFactory); var networkPeerFactory = new NetworkPeerFactory(network, dateTimeProvider, loggerFactory, new PayloadProvider().DiscoverPayloads(), new SelfEndpointTracker()); var peerAddressManager = new PeerAddressManager(DateTimeProvider.Default, nodeSettings.DataFolder, loggerFactory, new SelfEndpointTracker()); var peerDiscovery = new PeerDiscovery(new AsyncLoopFactory(loggerFactory), loggerFactory, network, networkPeerFactory, new NodeLifetime(), nodeSettings, peerAddressManager); var connectionSettings = new ConnectionManagerSettings(nodeSettings); var connectionManager = new ConnectionManager(dateTimeProvider, loggerFactory, network, networkPeerFactory, nodeSettings, new NodeLifetime(), new NetworkPeerConnectionParameters(), peerAddressManager, new IPeerConnector[] { }, peerDiscovery, connectionSettings, new VersionProvider()); var blockPuller = new LookaheadBlockPuller(chain, connectionManager, new LoggerFactory()); var peerBanning = new PeerBanning(connectionManager, loggerFactory, dateTimeProvider, peerAddressManager); var deployments = new NodeDeployments(network, chain); ConsensusRules consensusRules = new PowConsensusRules(network, loggerFactory, dateTimeProvider, chain, deployments, consensusSettings, new Checkpoints(), inMemoryCoinView, new Mock <ILookaheadBlockPuller>().Object).Register(); var consensusLoop = new ConsensusLoop(new AsyncLoopFactory(loggerFactory), new NodeLifetime(), chain, cachedCoinView, blockPuller, deployments, loggerFactory, new ChainState(new InvalidBlockHashStore(dateTimeProvider)), connectionManager, dateTimeProvider, new Signals.Signals(), consensusSettings, nodeSettings, peerBanning, consensusRules); await consensusLoop.StartAsync(); 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: PowBlockDefinition blockDefinition = new PowBlockDefinition(consensusLoop, dateTimeProvider, loggerFactory, mempool, mempoolLock, minerSettings, network, consensusRules); BlockTemplate newBlock = blockDefinition.Build(chain.Tip, scriptPubKey); chain.SetTip(newBlock.Block.Header); RuleContext ruleContext = consensusRules.CreateRuleContext(new ValidationContext { Block = newBlock.Block }, consensusLoop.Tip); ruleContext.MinedBlock = true; await consensusLoop.ValidateAndExecuteBlockAsync(ruleContext); List <BlockInfo> blockinfo = CreateBlockInfoList(); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) int baseheight = 0; 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); 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 == 0) { baseheight = chain.Height; } if (srcTxs.Count < 4) { srcTxs.Add(currentBlock.Transactions[0]); } currentBlock.UpdateMerkleRoot(); currentBlock.Header.Nonce = blockinfo[i].nonce; chain.SetTip(currentBlock.Header); RuleContext ruleContextForBlock = consensusRules.CreateRuleContext(new ValidationContext { Block = currentBlock }, consensusLoop.Tip); ruleContextForBlock.MinedBlock = true; await consensusLoop.ValidateAndExecuteBlockAsync(ruleContextForBlock); blocks.Add(currentBlock); } // Just to make sure we can still make simple blocks blockDefinition = new PowBlockDefinition(consensusLoop, dateTimeProvider, loggerFactory, mempool, mempoolLock, minerSettings, network, consensusRules); newBlock = blockDefinition.Build(chain.Tip, scriptPubKey); var mempoolValidator = new MempoolValidator(mempool, mempoolLock, dateTimeProvider, new MempoolSettings(nodeSettings), chain, cachedCoinView, loggerFactory, nodeSettings, consensusRules); return(new TestChainContext { MempoolValidator = mempoolValidator, SrcTxs = srcTxs }); }
/// <summary> /// Attempts to connect to a full BitCoin node and request any missing block headers. /// </summary> private static async Task <Node> ConnectNodeAndSyncHeaders(ConcurrentChain chain, CancellationToken ct) { logger.DebugFormat("Connecting to full node..."); ct.ThrowIfCancellationRequested(); ManualResetEventSlim headersSyncedSignal = new ManualResetEventSlim(); var parameters = new NodeConnectionParameters(); parameters.IsRelay = false; var scanLocation = new BlockLocator(); scanLocation.Blocks.Add(chain.Tip != null ? chain.Tip.HashBlock : _network.GetGenesis().GetHash()); var node = Node.ConnectToLocal(_network, parameters); logger.DebugFormat("Connected to node " + node.RemoteSocketEndpoint + "."); node.MessageReceived += (node1, message) => { ct.ThrowIfCancellationRequested(); switch (message.Message.Payload) { case HeadersPayload hdr: if (hdr.Headers != null && hdr.Headers.Count > 0) { logger.DebugFormat("Received {0} blocks start {1} to {2} height {3}.", hdr.Headers.Count, hdr.Headers.First().BlockTime, hdr.Headers.Last().BlockTime, chain.Height); scanLocation.Blocks.Clear(); scanLocation.Blocks.Add(hdr.Headers.Last().GetHash()); if (hdr != null) { var tip = chain.Tip; foreach (var header in hdr.Headers) { var prev = tip.FindAncestorOrSelf(header.HashPrevBlock); if (prev == null) { break; } tip = new ChainedBlock(header, header.GetHash(), prev); chain.SetTip(tip); ct.ThrowIfCancellationRequested(); } } var getHeadersPayload = new GetHeadersPayload(scanLocation); node.SendMessageAsync(getHeadersPayload); } else { // Headers synchronised. logger.DebugFormat("Block headers synchronised."); headersSyncedSignal.Set(); } break; case InvPayload inv: logger.DebugFormat("Inventory items {0}, first type {1}.", inv.Count(), inv.First().Type); if (inv.Any(x => x.Type == InventoryType.MSG_BLOCK)) { // New block available. var getHeadersPayload = new GetHeadersPayload(scanLocation); node.SendMessage(getHeadersPayload); } break; case MerkleBlockPayload merkleBlk: break; case TxPayload tx: break; default: logger.DebugFormat(message.Message.Command); break; } }; node.Disconnected += n => { logger.DebugFormat("Node disconnected, chain height " + chain.Height + "."); }; node.VersionHandshake(ct); node.PingPong(ct); logger.DebugFormat("Requesting block headers greater than height {0}.", chain.Height); node.SendMessage(new GetHeadersPayload(scanLocation)); logger.DebugFormat("Bitcoin node connected."); await Task.Run(() => { headersSyncedSignal.Wait(ct); }); return(node); }