예제 #1
0
        public void TestSimpleSpend()
        {
            using (var daemon = new TestDaemon())
            {
                // create a new keypair to spend to
                var toKeyPair    = daemon.TxManager.CreateKeyPair();
                var toPrivateKey = toKeyPair.Item1;
                var toPublicKey  = toKeyPair.Item2;

                // add some simple blocks
                var block1 = daemon.MineAndAddEmptyBlock(daemon.GenesisBlock);
                var block2 = daemon.MineAndAddEmptyBlock(block1);

                // check
                daemon.WaitForUpdate();
                AssertMethods.AssertDaemonAtBlock(2, block2.Hash, daemon.CoreDaemon);

                // attempt to spend block 2's coinbase in block 3
                var spendTx       = daemon.TxManager.CreateSpendTransaction(block2.Transactions[0], 0, (byte)ScriptHashType.SIGHASH_ALL, 50 * SATOSHI_PER_BTC, daemon.CoinbasePrivateKey, daemon.CoinbasePublicKey, toPublicKey);
                var block3Unmined = daemon.CreateEmptyBlock(block2)
                                    .WithAddedTransactions(spendTx);
                var block3 = daemon.MineAndAddBlock(block3Unmined);

                // check
                daemon.WaitForUpdate();
                AssertMethods.AssertDaemonAtBlock(3, block3.Hash, daemon.CoreDaemon);

                // add a simple block
                var block4 = daemon.MineAndAddEmptyBlock(block3);

                // check
                daemon.WaitForUpdate();
                AssertMethods.AssertDaemonAtBlock(4, block4.Hash, daemon.CoreDaemon);
            }
        }
예제 #2
0
        public void TestShorterChainWins()
        {
            using (var daemon = new TestDaemon())
            {
                // add some simple blocks
                var block1  = daemon.MineAndAddEmptyBlock();
                var block2  = daemon.MineAndAddEmptyBlock();
                var block3a = daemon.MineAndAddEmptyBlock();
                var block4a = daemon.MineAndAddEmptyBlock();
                var block5a = daemon.MineAndAddEmptyBlock();

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(5, block5a.Hash);

                // create a split with 3b, but do more work than current height 5 chain
                var testBlocksFork = daemon.TestBlocks.Fork(3);
                daemon.ChainParams.HighestTarget = UnitTestParams.Target2;
                var block3b = daemon.AddBlock(testBlocksFork.MineAndAddEmptyBlock(UnitTestParams.Target2));

                // check that blockchain reorganized to shorter chain
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(3, block3b.Hash);
            }
        }
예제 #3
0
        public void TestDoubleSpend()
        {
            using (var daemon = new TestDaemon())
            {
                // create a new keypair to spend to
                var toKeyPair    = daemon.TxManager.CreateKeyPair();
                var toPrivateKey = toKeyPair.Item1;
                var toPublicKey  = toKeyPair.Item2;

                // create a new keypair to double spend to
                var toKeyPairBad    = daemon.TxManager.CreateKeyPair();
                var toPrivateKeyBad = toKeyPair.Item1;
                var toPublicKeyBad  = toKeyPair.Item2;

                // add some simple blocks
                var block1 = daemon.MineAndAddEmptyBlock();
                var block2 = daemon.MineAndAddEmptyBlock();

                // add some blocks so coinbase is mature to spend
                Block lastBlock = null;
                for (var i = 0; i < 100; i++)
                {
                    lastBlock = daemon.MineAndAddEmptyBlock();
                }

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(102, lastBlock.Hash);

                // spend block 2's coinbase in block 3
                var spendTx       = daemon.TxManager.CreateSpendTransaction(block2.Transactions[0], 0, (byte)ScriptHashType.SIGHASH_ALL, 50 * SATOSHI_PER_BTC, daemon.CoinbasePrivateKey, daemon.CoinbasePublicKey, toPublicKey);
                var block3Unmined = daemon.CreateEmptyBlock(lastBlock.Hash)
                                    .CreateWithAddedTransactions(spendTx);
                var block3 = daemon.MineAndAddBlock(block3Unmined);

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(103, block3.Hash);

                // attempt to spend block 2's coinbase again in block 4
                var doubleSpendTx   = daemon.TxManager.CreateSpendTransaction(block2.Transactions[0], 0, (byte)ScriptHashType.SIGHASH_ALL, 50 * SATOSHI_PER_BTC, daemon.CoinbasePrivateKey, daemon.CoinbasePublicKey, toPublicKeyBad);
                var block4BadUmined = daemon.CreateEmptyBlock(block3.Hash)
                                      .CreateWithAddedTransactions(doubleSpendTx);
                var block4Bad = daemon.MineAndAddBlock(block4BadUmined);

                // check that bad block wasn't added
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(103, block3.Hash);

                // add a simple block
                daemon.TestBlocks.Rollback(1);
                var block4Good = daemon.MineAndAddEmptyBlock();

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(104, block4Good.Hash);
            }
        }
예제 #4
0
        public void TestDoubleSpend()
        {
            using (var daemon = new TestDaemon())
            {
                // create a new keypair to spend to
                var toKeyPair = daemon.TxManager.CreateKeyPair();
                var toPrivateKey = toKeyPair.Item1;
                var toPublicKey = toKeyPair.Item2;

                // create a new keypair to double spend to
                var toKeyPairBad = daemon.TxManager.CreateKeyPair();
                var toPrivateKeyBad = toKeyPair.Item1;
                var toPublicKeyBad = toKeyPair.Item2;

                // add some simple blocks
                var block1 = daemon.MineAndAddEmptyBlock();
                var block2 = daemon.MineAndAddEmptyBlock();

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(2, block2.Hash);

                // spend block 2's coinbase in block 3
                var spendTx = daemon.TxManager.CreateSpendTransaction(block2.Transactions[0], 0, (byte)ScriptHashType.SIGHASH_ALL, 50 * SATOSHI_PER_BTC, daemon.CoinbasePrivateKey, daemon.CoinbasePublicKey, toPublicKey);
                var block3Unmined = daemon.CreateEmptyBlock(block2.Hash)
                    .WithAddedTransactions(spendTx);
                var block3 = daemon.MineAndAddBlock(block3Unmined);

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(3, block3.Hash);

                // attempt to spend block 2's coinbase again in block 4
                var doubleSpendTx = daemon.TxManager.CreateSpendTransaction(block2.Transactions[0], 0, (byte)ScriptHashType.SIGHASH_ALL, 50 * SATOSHI_PER_BTC, daemon.CoinbasePrivateKey, daemon.CoinbasePublicKey, toPublicKeyBad);
                var block4BadUmined = daemon.CreateEmptyBlock(block3.Hash)
                    .WithAddedTransactions(doubleSpendTx);
                var block4Bad = daemon.MineAndAddBlock(block4BadUmined);

                // check that bad block wasn't added
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(3, block3.Hash);

                // add a simple block
                daemon.TestBlocks.Rollback(1);
                var block4Good = daemon.MineAndAddEmptyBlock();

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(4, block4Good.Hash);
            }
        }
예제 #5
0
        public void TestAddSingleBlock()
        {
            using (var daemon = new TestDaemon())
            {
                var block1 = daemon.MineAndAddEmptyBlock(daemon.GenesisBlock);

                daemon.WaitForUpdate();
                AssertMethods.AssertDaemonAtBlock(1, block1.Hash, daemon.CoreDaemon);
            }
        }
예제 #6
0
        public void TestAddSingleBlock()
        {
            using (var daemon = new TestDaemon())
            {
                var block1 = daemon.MineAndAddEmptyBlock();

                daemon.WaitForUpdate();
                daemon.AssertAtBlock(1, block1.Hash);
            }
        }
예제 #7
0
        public void TestAddSingleBlock()
        {
            using (var daemon = new TestDaemon())
            {
                var block1 = daemon.MineAndAddEmptyBlock();

                daemon.WaitForUpdate();
                daemon.AssertAtBlock(1, block1.Hash);
            }
        }
예제 #8
0
        public void TestSimpleSpend()
        {
            using (var daemon = new TestDaemon())
            {
                // create a new keypair to spend to
                var toKeyPair = daemon.TxManager.CreateKeyPair();
                var toPrivateKey = toKeyPair.Item1;
                var toPublicKey = toKeyPair.Item2;

                // add some simple blocks
                var block1 = daemon.MineAndAddEmptyBlock();
                var block2 = daemon.MineAndAddEmptyBlock();

                // add some blocks so coinbase is mature to spend
                Block lastBlock = null;
                for (var i = 0; i < 100; i++)
                    lastBlock = daemon.MineAndAddEmptyBlock();

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(102, lastBlock.Hash);

                // attempt to spend block 2's coinbase in block 3
                var spendTx = daemon.TxManager.CreateSpendTransaction(block2.Transactions[0], 0, (byte)ScriptHashType.SIGHASH_ALL, 50 * SATOSHI_PER_BTC, daemon.CoinbasePrivateKey, daemon.CoinbasePublicKey, toPublicKey);
                var block3Unmined = daemon.CreateEmptyBlock(lastBlock.Hash)
                    .CreateWithAddedTransactions(spendTx);
                var block3 = daemon.MineAndAddBlock(block3Unmined);

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(103, block3.Hash);

                // add a simple block
                var block4 = daemon.MineAndAddEmptyBlock();

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(104, block4.Hash);
            }
        }
예제 #9
0
        public void TestInsufficientBalance()
        {
            using (var daemon = new TestDaemon())
            {
                // create a new keypair to spend to
                var toKeyPair    = daemon.TxManager.CreateKeyPair();
                var toPrivateKey = toKeyPair.Item1;
                var toPublicKey  = toKeyPair.Item2;

                // add some simple blocks
                var block1 = daemon.MineAndAddEmptyBlock();
                var block2 = daemon.MineAndAddEmptyBlock();

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(2, block2.Hash);

                // attempt to spend block 2's coinbase in block 3, using twice its value
                var spendTx          = daemon.TxManager.CreateSpendTransaction(block2.Transactions[0], 0, (byte)ScriptHashType.SIGHASH_ALL, 100 * SATOSHI_PER_BTC, daemon.CoinbasePrivateKey, daemon.CoinbasePublicKey, toPublicKey);
                var block3BadUnmined = daemon.CreateEmptyBlock(block2.Hash)
                                       .CreateWithAddedTransactions(spendTx);
                var block3Bad = daemon.MineAndAddBlock(block3BadUnmined);

                // check that bad block wasn't added
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(2, block2.Hash);

                // add a simple block
                daemon.TestBlocks.Rollback(1);
                var block3Good = daemon.MineAndAddEmptyBlock();

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(3, block3Good.Hash);
            }
        }
예제 #10
0
        public void TestShorterChainWins()
        {
            using (var daemon = new TestDaemon())
            {
                // add some simple blocks
                var block1  = daemon.MineAndAddEmptyBlock(daemon.GenesisBlock);
                var block2  = daemon.MineAndAddEmptyBlock(block1);
                var block3a = daemon.MineAndAddEmptyBlock(block2);
                var block4a = daemon.MineAndAddEmptyBlock(block3a);
                var block5a = daemon.MineAndAddEmptyBlock(block4a);

                // check
                daemon.WaitForUpdate();
                AssertMethods.AssertDaemonAtBlock(5, block5a.Hash, daemon.CoreDaemon);

                // create a split with 3b, but do more work than current height 5 chain
                daemon.Rules.SetHighestTarget(UnitTestRules.Target2);
                var block3b = daemon.MineAndAddEmptyBlock(block2, UnitTestRules.Target2);

                // check that blockchain reorganized to shorter chain
                daemon.WaitForUpdate();
                AssertMethods.AssertDaemonAtBlock(3, block3b.Hash, daemon.CoreDaemon);
            }
        }
예제 #11
0
        public void TestLongBlockchain()
        {
            using (var daemon = new TestDaemon())
            {
                var count = 1.THOUSAND();

                var height = 0;
                var block  = daemon.GenesisBlock;
                for (var i = 0; i < count; i++)
                {
                    height++;
                    block = daemon.MineAndAddEmptyBlock();
                }

                daemon.WaitForUpdate();
                daemon.AssertAtBlock(height, block.Hash);
            }
        }
예제 #12
0
        public void TestLongBlockchain()
        {
            using (var daemon = new TestDaemon())
            {
                var count = 1.THOUSAND();

                var height = 0;
                var block = daemon.GenesisBlock;
                for (var i = 0; i < count; i++)
                {
                    height++;
                    block = daemon.MineAndAddEmptyBlock();
                }

                daemon.WaitForUpdate();
                daemon.AssertAtBlock(height, block.Hash);
            }
        }
예제 #13
0
        public void TestSimpleBlockchainSplit()
        {
            using (var daemon1 = new TestDaemon())
            {
                // add some simple blocks
                var block1  = daemon1.MineAndAddEmptyBlock();
                var block2  = daemon1.MineAndAddEmptyBlock();
                var block3a = daemon1.MineAndAddEmptyBlock();
                daemon1.WaitForUpdate();

                // create a fork test block chain, starting at block2
                var testBlocksFork = daemon1.TestBlocks.Fork(1);

                // wait for daemon
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(3, block3a.Hash);

                // introduce a tie split
                var block3b = daemon1.AddBlock(testBlocksFork.MineAndAddEmptyBlock());

                // check that 3a is still current as it was first
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(3, block3a.Hash);

                // continue with currently winning branch
                var block4a = daemon1.MineAndAddEmptyBlock();

                // wait for daemon
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(4, block4a.Hash);

                // continue with tied branch
                var block4b = daemon1.AddBlock(testBlocksFork.MineAndAddEmptyBlock());

                // check that 4a is still current as it was first
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(4, block4a.Hash);

                // resolve tie split, with other chain winning
                var block5b = daemon1.AddBlock(testBlocksFork.MineAndAddEmptyBlock());

                // check that blockchain reorged to the winning chain
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(5, block5b.Hash);

                // continue on winning fork
                var block6b = daemon1.AddBlock(testBlocksFork.MineAndAddEmptyBlock());

                // check that blockchain continued on the winning chain
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(6, block6b.Hash);

                // create a second blockchain, reusing the genesis from the first
                using (var daemon2 = new TestDaemon(daemon1.GenesisBlock))
                {
                    // add only the winning blocks to the second blockchain
                    daemon2.AddBlock(block1);
                    daemon2.AddBlock(block2);
                    daemon2.AddBlock(block3b);
                    daemon2.AddBlock(block4b);
                    daemon2.AddBlock(block5b);
                    daemon2.AddBlock(block6b);

                    // check second blockchain
                    daemon2.WaitForUpdate();
                    daemon2.AssertAtBlock(6, block6b.Hash);

                    // verify that re-organized blockchain matches winning-only blockchain
                    using (var expectedChainState = daemon2.CoreDaemon.GetChainState())
                        using (var actualChainState = daemon1.CoreDaemon.GetChainState())
                        {
                            var expectedUtxo = expectedChainState.ReadUnspentTransactions().ToList();
                            var actualUtxo   = actualChainState.ReadUnspentTransactions().ToList();

                            CollectionAssert.AreEqual(expectedUtxo, actualUtxo);
                        }
                }
            }
        }
예제 #14
0
        public void TestSimpleBlockchainSplit()
        {
            using (var daemon1 = new TestDaemon())
            {
                // add some simple blocks
                var block1 = daemon1.MineAndAddEmptyBlock();
                var block2 = daemon1.MineAndAddEmptyBlock();
                var block3a = daemon1.MineAndAddEmptyBlock();
                daemon1.WaitForUpdate();

                // create a fork test block chain, starting at block2
                var testBlocksFork = daemon1.TestBlocks.Fork(1);

                // wait for daemon
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(3, block3a.Hash);

                // introduce a tie split
                var block3b = daemon1.AddBlock(testBlocksFork.MineAndAddEmptyBlock());

                // check that 3a is still current as it was first
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(3, block3a.Hash);

                // continue with currently winning branch
                var block4a = daemon1.MineAndAddEmptyBlock();

                // wait for daemon
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(4, block4a.Hash);

                // continue with tied branch
                var block4b = daemon1.AddBlock(testBlocksFork.MineAndAddEmptyBlock());

                // check that 4a is still current as it was first
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(4, block4a.Hash);

                // resolve tie split, with other chain winning
                var block5b = daemon1.AddBlock(testBlocksFork.MineAndAddEmptyBlock());

                // check that blockchain reorged to the winning chain
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(5, block5b.Hash);

                // continue on winning fork
                var block6b = daemon1.AddBlock(testBlocksFork.MineAndAddEmptyBlock());

                // check that blockchain continued on the winning chain
                daemon1.WaitForUpdate();
                daemon1.AssertAtBlock(6, block6b.Hash);

                // create a second blockchain, reusing the genesis from the first
                using (var daemon2 = new TestDaemon(daemon1.GenesisBlock))
                {
                    // add only the winning blocks to the second blockchain
                    daemon2.AddBlock(block1);
                    daemon2.AddBlock(block2);
                    daemon2.AddBlock(block3b);
                    daemon2.AddBlock(block4b);
                    daemon2.AddBlock(block5b);
                    daemon2.AddBlock(block6b);

                    // check second blockchain
                    daemon2.WaitForUpdate();
                    daemon2.AssertAtBlock(6, block6b.Hash);

                    // verify that re-organized blockchain matches winning-only blockchain
                    using (var expectedChainState = daemon2.CoreDaemon.GetChainState())
                    using (var actualChainState = daemon1.CoreDaemon.GetChainState())
                    {
                        var expectedUtxo = expectedChainState.ReadUnspentTransactions().ToList();
                        var actualUtxo = actualChainState.ReadUnspentTransactions().ToList();

                        CollectionAssert.AreEqual(expectedUtxo, actualUtxo);
                    }
                }
            }
        }
예제 #15
0
        public void TestInsufficientBalance()
        {
            using (var daemon = new TestDaemon())
            {
                // create a new keypair to spend to
                var toKeyPair = daemon.TxManager.CreateKeyPair();
                var toPrivateKey = toKeyPair.Item1;
                var toPublicKey = toKeyPair.Item2;

                // add some simple blocks
                var block1 = daemon.MineAndAddEmptyBlock();
                var block2 = daemon.MineAndAddEmptyBlock();

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(2, block2.Hash);

                // attempt to spend block 2's coinbase in block 3, using twice its value
                var spendTx = daemon.TxManager.CreateSpendTransaction(block2.Transactions[0], 0, (byte)ScriptHashType.SIGHASH_ALL, 100 * SATOSHI_PER_BTC, daemon.CoinbasePrivateKey, daemon.CoinbasePublicKey, toPublicKey);
                var block3BadUnmined = daemon.CreateEmptyBlock(block2.Hash)
                    .CreateWithAddedTransactions(spendTx);
                var block3Bad = daemon.MineAndAddBlock(block3BadUnmined);

                // check that bad block wasn't added
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(2, block2.Hash);

                // add a simple block
                daemon.TestBlocks.Rollback(1);
                var block3Good = daemon.MineAndAddEmptyBlock();

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(3, block3Good.Hash);
            }
        }
예제 #16
0
        public void TestReplayBlockRollback()
        {
            var logger = LogManager.CreateNullLogger();

            using (var daemon = new TestDaemon())
            {
                // create a new keypair to spend to
                var toKeyPair = daemon.TxManager.CreateKeyPair();
                var toPrivateKey = toKeyPair.Item1;
                var toPublicKey = toKeyPair.Item2;

                // add block 1
                var block0 = daemon.GenesisBlock;
                var block1 = daemon.MineAndAddEmptyBlock();

                // add block 2, spending from block 1
                var spendTx1 = daemon.TxManager.CreateSpendTransaction(block1.Transactions[0], 0, (byte)ScriptHashType.SIGHASH_ALL, block1.Transactions[0].OutputValue(), daemon.CoinbasePrivateKey, daemon.CoinbasePublicKey, toPublicKey);
                var block2Unmined = daemon.CreateEmptyBlock(block1.Hash)
                    .WithAddedTransactions(spendTx1);
                var block2 = daemon.MineAndAddBlock(block2Unmined);

                // add block 3, spending from block 2
                var spendTx2 = daemon.TxManager.CreateSpendTransaction(block2.Transactions[1], 0, (byte)ScriptHashType.SIGHASH_ALL, block2.Transactions[1].OutputValue(), toPrivateKey, toPublicKey, toPublicKey);
                var block3Unmined = daemon.CreateEmptyBlock(block2.Hash)
                    .WithAddedTransactions(spendTx2);
                var block3 = daemon.MineAndAddBlock(block3Unmined);

                // replay all blocks up to block 3
                daemon.WaitForUpdate();
                using (var chainState = daemon.CoreDaemon.GetChainState())
                {
                    Assert.AreEqual(3, chainState.Chain.Height);

                    var replayTransactions = new List<LoadedTx>();
                    foreach (var blockHash in chainState.Chain.Blocks.Select(x => x.Hash))
                    {
                        replayTransactions.AddRange(BlockReplayer.ReplayBlock(daemon.CoreStorage, chainState, blockHash, replayForward: true)
                            .ToEnumerable());
                    }

                    // verify all transactions were replayed
                    Assert.AreEqual(6, replayTransactions.Count);
                    Assert.AreEqual(block0.Transactions[0].Hash, replayTransactions[0].Transaction.Hash);
                    Assert.AreEqual(block1.Transactions[0].Hash, replayTransactions[1].Transaction.Hash);
                    Assert.AreEqual(block2.Transactions[0].Hash, replayTransactions[2].Transaction.Hash);
                    Assert.AreEqual(block2.Transactions[1].Hash, replayTransactions[3].Transaction.Hash);
                    Assert.AreEqual(block3.Transactions[0].Hash, replayTransactions[4].Transaction.Hash);
                    Assert.AreEqual(block3.Transactions[1].Hash, replayTransactions[5].Transaction.Hash);
                }

                // mark blocks 2-3 invalid, they will be rolled back
                daemon.CoreStorage.MarkBlockInvalid(block3.Hash);
                daemon.CoreStorage.MarkBlockInvalid(block2.Hash);
                daemon.WaitForUpdate();

                // replay rollback of block 3
                using (var chainState = daemon.CoreDaemon.GetChainState())
                {
                    Assert.AreEqual(1, chainState.Chain.Height);

                    var replayTransactions = new List<LoadedTx>(
                        BlockReplayer.ReplayBlock(daemon.CoreStorage, chainState, block3.Hash, replayForward: false)
                        .ToEnumerable());

                    // verify transactions were replayed
                    Assert.AreEqual(2, replayTransactions.Count);
                    Assert.AreEqual(block3.Transactions[1].Hash, replayTransactions[0].Transaction.Hash);
                    Assert.AreEqual(block3.Transactions[0].Hash, replayTransactions[1].Transaction.Hash);

                    // verify correct previous output was replayed (block 3 tx 1 spent block 2 tx 1)
                    Assert.AreEqual(1, replayTransactions[0].InputTxes.Length);
                    CollectionAssert.AreEqual(block2.Transactions[1].Outputs[0].ScriptPublicKey, replayTransactions[0].GetInputPrevTxOutput(0).ScriptPublicKey);

                    // verify correct previous output was replayed (block 3 tx 0 spends nothing, coinbase)
                    Assert.AreEqual(0, replayTransactions[1].InputTxes.Length);
                }

                // replay rollback of block 2
                using (var chainState = daemon.CoreDaemon.GetChainState())
                {
                    Assert.AreEqual(1, chainState.Chain.Height);

                    var replayTransactions = new List<LoadedTx>(
                        BlockReplayer.ReplayBlock(daemon.CoreStorage, chainState, block2.Hash, replayForward: false)
                        .ToEnumerable());

                    // verify transactions were replayed
                    Assert.AreEqual(2, replayTransactions.Count);
                    Assert.AreEqual(block2.Transactions[1].Hash, replayTransactions[0].Transaction.Hash);
                    Assert.AreEqual(block2.Transactions[0].Hash, replayTransactions[1].Transaction.Hash);

                    // verify correct previous output was replayed (block 2 tx 1 spent block 1 tx 0)
                    Assert.AreEqual(1, replayTransactions[0].InputTxes.Length);
                    CollectionAssert.AreEqual(block1.Transactions[0].Outputs[0].ScriptPublicKey, replayTransactions[0].GetInputPrevTxOutput(0).ScriptPublicKey);

                    // verify correct previous output was replayed (block 2 tx 0 spends nothing, coinbase)
                    Assert.AreEqual(0, replayTransactions[1].InputTxes.Length);
                }
            }
        }
예제 #17
0
        public void TestReplayBlockRollback()
        {
            using (var daemon = new TestDaemon())
            {
                // create a new keypair to spend to
                var toKeyPair    = daemon.TxManager.CreateKeyPair();
                var toPrivateKey = toKeyPair.Item1;
                var toPublicKey  = toKeyPair.Item2;

                // add block 1
                var block0 = daemon.GenesisBlock;
                var block1 = daemon.MineAndAddEmptyBlock();

                // add some blocks so coinbase is mature to spend
                Block lastBlock = null;
                for (var i = 0; i < 100; i++)
                {
                    lastBlock = daemon.MineAndAddEmptyBlock();
                }

                // add block 2, spending from block 1
                var spendTx1      = daemon.TxManager.CreateSpendTransaction(block1.Transactions[0], 0, (byte)ScriptHashType.SIGHASH_ALL, block1.Transactions[0].OutputValue(), daemon.CoinbasePrivateKey, daemon.CoinbasePublicKey, toPublicKey);
                var block2Unmined = daemon.CreateEmptyBlock(lastBlock.Hash)
                                    .CreateWithAddedTransactions(spendTx1);
                var block2 = daemon.MineAndAddBlock(block2Unmined);

                // add some blocks so coinbase is mature to spend
                for (var i = 0; i < 100; i++)
                {
                    lastBlock = daemon.MineAndAddEmptyBlock();
                }

                // add block 3, spending from block 2
                var spendTx2      = daemon.TxManager.CreateSpendTransaction(block2.Transactions[1], 0, (byte)ScriptHashType.SIGHASH_ALL, block2.Transactions[1].OutputValue(), toPrivateKey, toPublicKey, toPublicKey);
                var block3Unmined = daemon.CreateEmptyBlock(lastBlock.Hash)
                                    .CreateWithAddedTransactions(spendTx2);
                var block3 = daemon.MineAndAddBlock(block3Unmined);

                // replay all blocks up to block 3
                daemon.WaitForUpdate();
                using (var chainState = daemon.CoreDaemon.GetChainState())
                {
                    Assert.AreEqual(203, chainState.Chain.Height);

                    var replayTransactions = new List <ValidatableTx>();
                    foreach (var blockHash in chainState.Chain.Blocks.Select(x => x.Hash))
                    {
                        replayTransactions.AddRange(BlockReplayer.ReplayBlock(daemon.CoreStorage, chainState, blockHash, replayForward: true)
                                                    .ToEnumerable());
                    }

                    // verify all transactions were replayed
                    Assert.AreEqual(206, replayTransactions.Count);
                    Assert.AreEqual(block0.Transactions[0].Hash, replayTransactions[0].Transaction.Hash);
                    Assert.AreEqual(block1.Transactions[0].Hash, replayTransactions[1].Transaction.Hash);
                    Assert.AreEqual(block2.Transactions[0].Hash, replayTransactions[102].Transaction.Hash);
                    Assert.AreEqual(block2.Transactions[1].Hash, replayTransactions[103].Transaction.Hash);
                    Assert.AreEqual(block3.Transactions[0].Hash, replayTransactions[204].Transaction.Hash);
                    Assert.AreEqual(block3.Transactions[1].Hash, replayTransactions[205].Transaction.Hash);
                }

                // mark block 2 invalid, it will be rolled back
                daemon.CoreStorage.MarkBlockInvalid(block2.Hash, daemon.CoreDaemon.TargetChain);
                daemon.WaitForUpdate();

                // replay rollback of block 3
                using (var chainState = daemon.CoreDaemon.GetChainState())
                {
                    Assert.AreEqual(101, chainState.Chain.Height);

                    var replayTransactions = new List <ValidatableTx>(
                        BlockReplayer.ReplayBlock(daemon.CoreStorage, chainState, block3.Hash, replayForward: false)
                        .ToEnumerable());

                    // verify transactions were replayed
                    Assert.AreEqual(2, replayTransactions.Count);
                    Assert.AreEqual(block3.Transactions[1].Hash, replayTransactions[0].Transaction.Hash);
                    Assert.AreEqual(block3.Transactions[0].Hash, replayTransactions[1].Transaction.Hash);

                    // verify correct previous output was replayed (block 3 tx 1 spent block 2 tx 1)
                    Assert.AreEqual(1, replayTransactions[0].PrevTxOutputs.Length);
                    CollectionAssert.AreEqual(block2.Transactions[1].Outputs[0].ScriptPublicKey, replayTransactions[0].PrevTxOutputs[0].ScriptPublicKey);

                    // verify correct previous output was replayed (block 3 tx 0 spends nothing, coinbase)
                    Assert.AreEqual(0, replayTransactions[1].PrevTxOutputs.Length);
                }

                // replay rollback of block 2
                using (var chainState = daemon.CoreDaemon.GetChainState())
                {
                    Assert.AreEqual(101, chainState.Chain.Height);

                    var replayTransactions = new List <ValidatableTx>(
                        BlockReplayer.ReplayBlock(daemon.CoreStorage, chainState, block2.Hash, replayForward: false)
                        .ToEnumerable());

                    // verify transactions were replayed
                    Assert.AreEqual(2, replayTransactions.Count);
                    Assert.AreEqual(block2.Transactions[1].Hash, replayTransactions[0].Transaction.Hash);
                    Assert.AreEqual(block2.Transactions[0].Hash, replayTransactions[1].Transaction.Hash);

                    // verify correct previous output was replayed (block 2 tx 1 spent block 1 tx 0)
                    Assert.AreEqual(1, replayTransactions[0].PrevTxOutputs.Length);
                    CollectionAssert.AreEqual(block1.Transactions[0].Outputs[0].ScriptPublicKey, replayTransactions[0].PrevTxOutputs[0].ScriptPublicKey);

                    // verify correct previous output was replayed (block 2 tx 0 spends nothing, coinbase)
                    Assert.AreEqual(0, replayTransactions[1].PrevTxOutputs.Length);
                }
            }
        }
예제 #18
0
        public void TestShorterChainWins()
        {
            using (var daemon = new TestDaemon())
            {
                // add some simple blocks
                var block1 = daemon.MineAndAddEmptyBlock();
                var block2 = daemon.MineAndAddEmptyBlock();
                var block3a = daemon.MineAndAddEmptyBlock();
                var block4a = daemon.MineAndAddEmptyBlock();
                var block5a = daemon.MineAndAddEmptyBlock();

                // check
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(5, block5a.Hash);

                // create a split with 3b, but do more work than current height 5 chain
                var testBlocksFork = daemon.TestBlocks.Fork(3);
                daemon.ChainParams.HighestTarget = UnitTestParams.Target2;
                var block3b = daemon.AddBlock(testBlocksFork.MineAndAddEmptyBlock(UnitTestParams.Target2));

                // check that blockchain reorganized to shorter chain
                daemon.WaitForUpdate();
                daemon.AssertAtBlock(3, block3b.Hash);
            }
        }