private Block createNextBlock(Block baseBlock, int nextBlockHeight, TransactionOutPointWithValue prevOut, Money additionalCoinbaseValue) { int height = 0; if (blockToHeightMap.TryGetValue(baseBlock.GetHash(), out height)) { Assert.True(height == nextBlockHeight - 1); } var coinbaseValue = Network.GetReward(nextBlockHeight) + (additionalCoinbaseValue ?? Money.Zero); Block block = baseBlock.CreateNextBlockWithCoinbase(coinbaseOutKeyPubKey, coinbaseValue); if (prevOut != null) { Transaction t = new Transaction(); // Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much t.AddOutput(new TxOut(new Money(0), new Script(Op.GetPushOp(1)))); t.AddOutput(new TxOut(Money.Parse("1"), new PayToPubkeyHashTemplate().GenerateScriptPubKey(coinbaseOutKeyPubKey))); // Spendable output t.AddOutput(new TxOut(Money.Zero, new Script(Op.GetPushOp(1)))); addOnlyInputToTransaction(t, prevOut); block.AddTransaction(t); block.ComputeMerkleRoot(); } return(block); }
private void addOnlyInputToTransaction(Transaction t, TransactionOutPointWithValue prevOut, uint sequence) { TxIn input = new TxIn(prevOut.outpoint) { ScriptSig = new Script(Op.GetPushOp(0)) }; input.Sequence = sequence; t.AddInput(input); var hash = prevOut.scriptPubKey.SignatureHash(t, 0, SigHash.All); input.ScriptSig = new PayToPubkeyHashTemplate().GenerateScriptSig(new TransactionSignature(coinbaseOutKey.Sign(hash), SigHash.All), coinbaseOutKeyPubKey); }
private void addOnlyInputToTransaction(Transaction t, TransactionOutPointWithValue prevOut) { addOnlyInputToTransaction(t, prevOut, TxIn.NO_SEQUENCE); }
internal RuleList GetBlocksToTest(bool addSigExpensiveBlocks, bool runLargeReorgs) { List <Rule> blocks = new List <Rule>(); RuleList ret = new RuleList(blocks, hashHeaderMap, 10); Queue <TransactionOutPointWithValue> spendableOutputs = new Queue <TransactionOutPointWithValue>(); int chainHeadHeight = 1; Block chainHead = Network.GetGenesis().CreateNextBlockWithCoinbase(coinbaseOutKeyPubKey, Money.Parse("50")); blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, chainHead, true, false, chainHead.GetHash(), 1, "Initial Block")); spendableOutputs.Enqueue(new TransactionOutPointWithValue( new OutPoint(chainHead.Transactions[0].GetHash(), 0), Money.Parse("50"), chainHead.Transactions[0].Outputs[0].ScriptPubKey)); for (int i = 1; i < Network.SpendableCoinbaseDepth; i++) { chainHead = chainHead.CreateNextBlockWithCoinbase(coinbaseOutKeyPubKey, Money.Parse("50")); chainHeadHeight++; blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, chainHead, true, false, chainHead.GetHash(), i + 1, "Initial Block chain output generation")); spendableOutputs.Enqueue(new TransactionOutPointWithValue( new OutPoint(chainHead.Transactions[0].GetHash(), 0), Money.Parse("50"), chainHead.Transactions.First().Outputs.First().ScriptPubKey)); } // Start by building a couple of blocks on top of the genesis block. Block b1 = createNextBlock(chainHead, chainHeadHeight + 1, spendableOutputs.Dequeue(), null); blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, b1, true, false, b1.GetHash(), chainHeadHeight + 1, "b1")); spendableOutputs.Enqueue(new TransactionOutPointWithValue( new OutPoint(b1.Transactions[0].GetHash(), 0), b1.Transactions[0].Outputs[0].Value, b1.Transactions[0].Outputs[0].ScriptPubKey)); TransactionOutPointWithValue out1 = spendableOutputs.Dequeue(); Assert.True(out1 != null); Block b2 = createNextBlock(b1, chainHeadHeight + 2, out1, null); blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, b2, true, false, b2.GetHash(), chainHeadHeight + 2, "b2")); // Make sure nothing funky happens if we try to re-add b2 blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, b2, true, false, b2.GetHash(), chainHeadHeight + 2, "b2")); spendableOutputs.Enqueue(new TransactionOutPointWithValue( new OutPoint(b2.Transactions[0].GetHash(), 0), b2.Transactions[0].Outputs[0].Value, b2.Transactions[0].Outputs[0].ScriptPubKey)); // We now have the following chain (which output is spent is in parentheses): // genesis -> b1 (0) -> b2 (1) // // so fork like this: // // genesis -> b1 (0) -> b2 (1) // \-> b3 (1) // // Nothing should happen at this point. We saw b2 first so it takes priority. Block b3 = createNextBlock(b1, chainHeadHeight + 2, out1, null); blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, b3, true, false, b2.GetHash(), chainHeadHeight + 2, "b3")); // Make sure nothing breaks if we add b3 twice blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, b3, true, false, b2.GetHash(), chainHeadHeight + 2, "b3")); // Now we add another block to make the alternative chain longer. TransactionOutPointWithValue out2 = spendableOutputs.Dequeue(); Assert.True(out2 != null); Block b4 = createNextBlock(b3, chainHeadHeight + 3, out2, null); blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, b4, true, false, b4.GetHash(), chainHeadHeight + 3, "b4")); // // genesis -> b1 (0) -> b2 (1) // \-> b3 (1) -> b4 (2) // // ... and back to the first chain. Block b5 = createNextBlock(b2, chainHeadHeight + 3, out2, null); blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, b5, true, false, b4.GetHash(), chainHeadHeight + 3, "b5")); spendableOutputs.Enqueue(new TransactionOutPointWithValue( new OutPoint(b5.Transactions[0].GetHash(), 0), b5.Transactions[0].Outputs[0].Value, b5.Transactions[0].Outputs[0].ScriptPubKey)); TransactionOutPointWithValue out3 = spendableOutputs.Dequeue(); Block b6 = createNextBlock(b5, chainHeadHeight + 4, out3, null); blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, b6, true, false, b6.GetHash(), chainHeadHeight + 4, "b6")); // // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) // \-> b3 (1) -> b4 (2) // // Try to create a fork that double-spends // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) // \-> b7 (3) -> b8 (4) // \-> b3 (1) -> b4 (2) // Block b7 = createNextBlock(b5, chainHeadHeight + 4, out2, null); blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, b7, true, false, b6.GetHash(), chainHeadHeight + 4, "b7")); TransactionOutPointWithValue out4 = spendableOutputs.Dequeue(); Block b8 = createNextBlock(b7, chainHeadHeight + 5, out4, null); blocks.Add(new BlockAndValidity(blockToHeightMap, hashHeaderMap, b8, false, true, b6.GetHash(), chainHeadHeight + 4, "b8")); return(ret); }
private Block createNextBlock(Block baseBlock, int nextBlockHeight, TransactionOutPointWithValue prevOut, Money additionalCoinbaseValue) { int height = 0; if(blockToHeightMap.TryGetValue(baseBlock.GetHash(), out height)) Assert.True(height == nextBlockHeight - 1); var coinbaseValue = Network.GetReward(nextBlockHeight) + (additionalCoinbaseValue ?? Money.Zero); Block block = baseBlock.CreateNextBlockWithCoinbase(coinbaseOutKeyPubKey, coinbaseValue); if(prevOut != null) { Transaction t = new Transaction(); // Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much t.AddOutput(new TxOut(new Money(0), new Script(Op.GetPushOp(1)))); t.AddOutput(new TxOut(Money.Parse("1"), new PayToPubkeyHashTemplate().GenerateScriptPubKey(coinbaseOutKeyPubKey))); // Spendable output t.AddOutput(new TxOut(Money.Zero, new Script(Op.GetPushOp(1)))); addOnlyInputToTransaction(t, prevOut); block.AddTransaction(t); block.ComputeMerkleRoot(); } return block; }
private void addOnlyInputToTransaction(Transaction t, TransactionOutPointWithValue prevOut, uint sequence) { TxIn input = new TxIn(prevOut.outpoint) { ScriptSig = new Script(Op.GetPushOp(0)) }; input.Sequence = sequence; t.AddInput(input); var hash = prevOut.scriptPubKey.SignatureHash(t, 0, SigHash.All); input.ScriptSig = new PayToPubkeyHashTemplate().GenerateScriptSig(new TransactionSignature(coinbaseOutKey.Sign(hash), SigHash.All),coinbaseOutKeyPubKey); }