Example #1
0
        public void TestHeight()
        {
            var fakeHeaders = new FakeHeaders();
            var header0     = fakeHeaders.GenesisChained();
            var header1     = fakeHeaders.NextChained();

            var chainBuilder = new ChainBuilder();

            // verify height with 0 blocks
            var chainEmpty = chainBuilder.ToImmutable();

            Assert.AreEqual(-1, chainEmpty.Height);

            // verify height with 1 block
            chainBuilder.AddBlock(header0);
            var chain0 = chainBuilder.ToImmutable();

            Assert.AreEqual(0, chain0.Height);

            // verify height with 2 blocks
            chainBuilder.AddBlock(header1);
            var chain1 = chainBuilder.ToImmutable();

            Assert.AreEqual(1, chain1.Height);
        }
Example #2
0
        public void TestTotalWork()
        {
            var fakeHeaders = new FakeHeaders();
            var header0     = fakeHeaders.GenesisChained();
            var header1     = fakeHeaders.NextChained();
            var totalWork0  = DataCalculator.CalculateWork(header0);
            var totalWork1  = totalWork0 + DataCalculator.CalculateWork(header1);

            var chainBuilder = new ChainBuilder();

            // verify total work with 0 blocks
            var chainEmpty = chainBuilder.ToImmutable();

            Assert.AreEqual(0, chainEmpty.TotalWork);

            // verify total work with 1 block
            chainBuilder.AddBlock(header0);
            var chain0 = chainBuilder.ToImmutable();

            Assert.AreEqual(totalWork0.ToBigInteger(), chain0.TotalWork);

            // verify total work with 2 blocks
            chainBuilder.AddBlock(header1);
            var chain1 = chainBuilder.ToImmutable();

            Assert.AreEqual(totalWork1.ToBigInteger(), chain1.TotalWork);
        }
Example #3
0
        public void TestToBuilder()
        {
            var fakeHeaders = new FakeHeaders();
            var header0     = fakeHeaders.GenesisChained();
            var header1     = fakeHeaders.NextChained();

            var chainBuilder = new ChainBuilder();

            // verify to builder with 0 blocks
            var chainEmpty        = chainBuilder.ToImmutable();
            var chainBuilderEmpty = chainEmpty.ToBuilder();

            Assert.AreEqual(0, chainBuilderEmpty.Blocks.Count);
            Assert.AreEqual(0, chainBuilderEmpty.BlocksByHash.Count);

            // verify to builder with 1 block
            chainBuilder.AddBlock(header0);
            var chain0        = chainBuilder.ToImmutable();
            var chainBuilder0 = chain0.ToBuilder();

            CollectionAssert.AreEqual(new[] { header0 }, chainBuilder0.Blocks);
            CollectionAssert.AreEquivalent(new Dictionary <UInt256, ChainedHeader> {
                { header0.Hash, header0 }
            }, chainBuilder0.BlocksByHash);

            // verify to builder with 2 blocks
            chainBuilder.AddBlock(header1);
            var chain1        = chainBuilder.ToImmutable();
            var chainBuilder1 = chain1.ToBuilder();

            CollectionAssert.AreEqual(new[] { header0, header1 }, chainBuilder1.Blocks);
            CollectionAssert.AreEquivalent(new Dictionary <UInt256, ChainedHeader> {
                { header0.Hash, header0 }, { header1.Hash, header1 }
            }, chainBuilder1.BlocksByHash);
        }
Example #4
0
        public void TestLastBlock()
        {
            var fakeHeaders = new FakeHeaders();
            var header0     = fakeHeaders.GenesisChained();
            var header1     = fakeHeaders.NextChained();

            var chainBuilder = new ChainBuilder();

            // verify last block with 0 blocks
            var chainEmpty = chainBuilder.ToImmutable();

            Assert.IsNull(chainEmpty.LastBlock);

            // verify last block with 1 block
            chainBuilder.AddBlock(header0);
            var chain0 = chainBuilder.ToImmutable();

            Assert.AreEqual(header0, chain0.LastBlock);

            // verify last block with 2 blocks
            chainBuilder.AddBlock(header1);
            var chain1 = chainBuilder.ToImmutable();

            Assert.AreEqual(header1, chain1.LastBlock);
        }
Example #5
0
        public void TestBlocks()
        {
            var fakeHeaders = new FakeHeaders();
            var header0     = fakeHeaders.GenesisChained();
            var header1     = fakeHeaders.NextChained();

            var chainBuilder = new ChainBuilder();

            // verify block list with 0 blocks
            var chainEmpty = chainBuilder.ToImmutable();

            Assert.AreEqual(0, chainEmpty.Blocks.Count);

            // verify block list with 1 block
            chainBuilder.AddBlock(header0);
            var chain0 = chainBuilder.ToImmutable();

            CollectionAssert.AreEqual(new[] { header0 }, chain0.Blocks);

            // verify block list with 2 blocks
            chainBuilder.AddBlock(header1);
            var chain1 = chainBuilder.ToImmutable();

            CollectionAssert.AreEqual(new[] { header0, header1 }, chain1.Blocks);
        }
Example #6
0
        /// <summary>
        /// Create a new Chain instance consisting of a single genesis header.
        /// </summary>
        /// <param name="genesisBlock">The genesis header.</param>
        /// <returns>The Chain instance.</returns>
        public static Chain CreateForGenesisBlock(ChainedHeader genesisBlock)
        {
            var chainBuilder = new ChainBuilder();

            chainBuilder.AddBlock(genesisBlock);
            return(chainBuilder.ToImmutable());
        }
Example #7
0
        public void TestAddBlockInvalid()
        {
            var fakeHeaders = new FakeHeaders();
            var header0     = fakeHeaders.GenesisChained();
            var header1     = fakeHeaders.NextChained();
            var header2     = fakeHeaders.NextChained();

            var chainBuilder = new ChainBuilder();

            // adding header 1 first should fail
            AssertMethods.AssertThrows <InvalidOperationException>(() => chainBuilder.AddBlock(header1));

            // add header 0
            chainBuilder.AddBlock(header0);

            // adding header 2 without header 1 should fail
            AssertMethods.AssertThrows <InvalidOperationException>(() => chainBuilder.AddBlock(header2));
        }
Example #8
0
        public void TestGenesisBlock()
        {
            var fakeHeaders = new FakeHeaders();
            var header0     = fakeHeaders.GenesisChained();
            var header1     = fakeHeaders.NextChained();

            var chainBuilder = new ChainBuilder();

            // verify genesis with 0 blocks
            Assert.IsNull(chainBuilder.GenesisBlock);

            // verify genesis with 1 block
            chainBuilder.AddBlock(header0);
            Assert.AreEqual(header0, chainBuilder.GenesisBlock);

            // verify genesis with 2 blocks
            chainBuilder.AddBlock(header1);
            Assert.AreEqual(header0, chainBuilder.GenesisBlock);
        }
Example #9
0
        public void TestDoubleSpend()
        {
            // prepare block
            var fakeHeaders      = new FakeHeaders();
            var chainedHeader0   = fakeHeaders.GenesisChained();
            var chainedHeader1   = fakeHeaders.NextChained();
            var chain            = new ChainBuilder();
            var emptyCoinbaseTx0 = new Transaction(0, ImmutableArray.Create <TxInput>(), ImmutableArray.Create <TxOutput>(), 0);
            var emptyCoinbaseTx1 = new Transaction(1, ImmutableArray.Create <TxInput>(), ImmutableArray.Create <TxOutput>(), 0);

            // initialize memory utxo builder storage
            var memoryStorage          = new MemoryStorageManager();
            var memoryChainStateCursor = memoryStorage.OpenChainStateCursor().Item;

            // initialize utxo builder
            var utxoBuilder = new UtxoBuilder(memoryChainStateCursor, LogManager.CreateNullLogger());

            // prepare an unspent transaction
            var txHash    = new UInt256(100);
            var unspentTx = new UnspentTx(txHash, chainedHeader0.Height, 0, 1, OutputState.Unspent);

            // add the unspent transaction
            memoryChainStateCursor.TryAddUnspentTx(unspentTx);

            // create an input to spend the unspent transaction
            var input = new TxInput(new TxOutputKey(txHash, txOutputIndex: 0), ImmutableArray.Create <byte>(), 0);
            var tx    = new Transaction(0, ImmutableArray.Create(input), ImmutableArray.Create <TxOutput>(), 0);

            // spend the input
            chain.AddBlock(chainedHeader0);
            utxoBuilder.CalculateUtxo(chain.ToImmutable(), new[] { emptyCoinbaseTx0, tx }).ToList();

            // verify utxo storage
            Assert.IsFalse(memoryChainStateCursor.ContainsUnspentTx(txHash));

            // attempt to spend the input again
            chain.AddBlock(chainedHeader1);
            utxoBuilder.CalculateUtxo(chain.ToImmutable(), new[] { emptyCoinbaseTx1, tx }).ToList();

            // validation exception should be thrown
        }
Example #10
0
        public void TestAddBlock()
        {
            var fakeHeaders = new FakeHeaders();
            var header0     = fakeHeaders.GenesisChained();
            var header1     = fakeHeaders.NextChained();

            var chainBuilder = new ChainBuilder();

            // add header 0 and verify
            chainBuilder.AddBlock(header0);
            CollectionAssert.AreEqual(new[] { header0 }, chainBuilder.Blocks);
            CollectionAssert.AreEquivalent(new Dictionary <UInt256, ChainedHeader> {
                { header0.Hash, header0 }
            }, chainBuilder.BlocksByHash);

            // add header 1 and verify
            chainBuilder.AddBlock(header1);
            CollectionAssert.AreEqual(new[] { header0, header1 }, chainBuilder.Blocks);
            CollectionAssert.AreEquivalent(new Dictionary <UInt256, ChainedHeader> {
                { header0.Hash, header0 }, { header1.Hash, header1 }
            }, chainBuilder.BlocksByHash);
        }
Example #11
0
        public static bool TryReadChain(UInt256 blockHash, out Chain chain, Func <UInt256, ChainedHeader> getChainedHeader)
        {
            // return an empty chain for null blockHash
            // when retrieving a chain by its tip, a null tip represents an empty chain
            if (blockHash == null)
            {
                chain = new ChainBuilder().ToImmutable();
                return(true);
            }

            var retrievedHeaders = new List <ChainedHeader>();

            var chainedHeader = getChainedHeader(blockHash);

            if (chainedHeader != null)
            {
                var expectedHeight = chainedHeader.Height;
                do
                {
                    if (chainedHeader.Height != expectedHeight)
                    {
                        chain = default(Chain);
                        return(false);
                    }

                    retrievedHeaders.Add(chainedHeader);
                    expectedHeight--;
                }while (expectedHeight >= 0 && chainedHeader.PreviousBlockHash != chainedHeader.Hash &&
                        (chainedHeader = getChainedHeader(chainedHeader.PreviousBlockHash)) != null);

                if (retrievedHeaders.Last().Height != 0)
                {
                    chain = default(Chain);
                    return(false);
                }

                var chainBuilder = new ChainBuilder();
                for (var i = retrievedHeaders.Count - 1; i >= 0; i--)
                {
                    chainBuilder.AddBlock(retrievedHeaders[i]);
                }

                chain = chainBuilder.ToImmutable();
                return(true);
            }
            else
            {
                chain = default(Chain);
                return(false);
            }
        }
Example #12
0
        public TestBlocks(Block genesisBlock = null)
        {
            // create the key pair that block rewards will be sent to
            var keyPair = txManager.CreateKeyPair();

            coinbasePrivateKey = keyPair.Item1;
            coinbasePublicKey  = keyPair.Item2;

            // create and mine the genesis block
            genesisBlock = genesisBlock ?? MineEmptyBlock(UInt256.Zero);

            // initialize unit test rules
            rules = new UnitTestRules()
            {
                // disable execution of rules validation
                ValidateTransactionAction         = (_, __) => { },
                ValidationTransactionScriptAction = (_, __, ___, ____, _____) => { }
            };
            ChainParams.SetGenesisBlock(genesisBlock);

            blocks.Add(genesisBlock);
            chain.AddBlock(ChainParams.GenesisChainedHeader);
        }
Example #13
0
        public void TestBlocksByHash()
        {
            var fakeHeaders = new FakeHeaders();
            var header0     = fakeHeaders.GenesisChained();
            var header1     = fakeHeaders.NextChained();

            var chainBuilder = new ChainBuilder();

            // verify blocks dictionary with 0 blocks
            Assert.AreEqual(0, chainBuilder.BlocksByHash.Count);

            // verify blocks dictionary with 1 block
            chainBuilder.AddBlock(header0);
            CollectionAssert.AreEquivalent(new Dictionary <UInt256, ChainedHeader> {
                { header0.Hash, header0 }
            }, chainBuilder.BlocksByHash);

            // verify blocks dictionary with 2 blocks
            chainBuilder.AddBlock(header1);
            CollectionAssert.AreEquivalent(new Dictionary <UInt256, ChainedHeader> {
                { header0.Hash, header0 }, { header1.Hash, header1 }
            }, chainBuilder.BlocksByHash);
        }
Example #14
0
        public void TestRemoveBlockInvalid()
        {
            var fakeHeaders = new FakeHeaders();
            var header0     = fakeHeaders.GenesisChained();
            var header1     = fakeHeaders.NextChained();
            var header2     = fakeHeaders.NextChained();

            var chainBuilder = new ChainBuilder(new[] { header0, header1, header2 });

            // removing header 1 first should fail
            AssertMethods.AssertThrows <InvalidOperationException>(() => chainBuilder.RemoveBlock(header1));

            // remove header 2
            chainBuilder.RemoveBlock(header2);

            // removing header 0 with header 1 present should fail
            AssertMethods.AssertThrows <InvalidOperationException>(() => chainBuilder.AddBlock(header0));
        }
Example #15
0
        public void TestSimpleSpend()
        {
            // prepare block
            var fakeHeaders      = new FakeHeaders();
            var chainedHeader0   = fakeHeaders.GenesisChained();
            var chainedHeader1   = fakeHeaders.NextChained();
            var chainedHeader2   = fakeHeaders.NextChained();
            var chain            = new ChainBuilder();
            var emptyCoinbaseTx0 = new Transaction(0, ImmutableArray.Create <TxInput>(), ImmutableArray.Create <TxOutput>(), 0);
            var emptyCoinbaseTx1 = new Transaction(1, ImmutableArray.Create <TxInput>(), ImmutableArray.Create <TxOutput>(), 0);
            var emptyCoinbaseTx2 = new Transaction(2, ImmutableArray.Create <TxInput>(), ImmutableArray.Create <TxOutput>(), 0);

            // initialize memory utxo builder storage
            var memoryStorage          = new MemoryStorageManager();
            var memoryChainStateCursor = memoryStorage.OpenChainStateCursor().Item;

            // initialize utxo builder
            var utxoBuilder = new UtxoBuilder(memoryChainStateCursor, LogManager.CreateNullLogger());

            // prepare an unspent transaction
            var txHash    = new UInt256(100);
            var unspentTx = new UnspentTx(txHash, chainedHeader0.Height, 0, 3, OutputState.Unspent);

            // prepare unspent output
            var unspentTransactions = ImmutableDictionary.Create <UInt256, UnspentTx>().Add(txHash, unspentTx);

            // add the unspent transaction
            memoryChainStateCursor.TryAddUnspentTx(unspentTx);

            // create an input to spend the unspent transaction's first output
            var input0 = new TxInput(new TxOutputKey(txHash, txOutputIndex: 0), ImmutableArray.Create <byte>(), 0);
            var tx0    = new Transaction(0, ImmutableArray.Create(input0), ImmutableArray.Create <TxOutput>(), 0);

            // spend the input
            chain.AddBlock(chainedHeader0);
            utxoBuilder.CalculateUtxo(chain.ToImmutable(), new[] { emptyCoinbaseTx0, tx0 }).ToList();

            // verify utxo storage
            UnspentTx actualUnspentTx;

            Assert.IsTrue(memoryChainStateCursor.TryGetUnspentTx(txHash, out actualUnspentTx));
            Assert.IsTrue(actualUnspentTx.OutputStates.Length == 3);
            Assert.IsTrue(actualUnspentTx.OutputStates[0] == OutputState.Spent);
            Assert.IsTrue(actualUnspentTx.OutputStates[1] == OutputState.Unspent);
            Assert.IsTrue(actualUnspentTx.OutputStates[2] == OutputState.Unspent);

            // create an input to spend the unspent transaction's second output
            var input1 = new TxInput(new TxOutputKey(txHash, txOutputIndex: 1), ImmutableArray.Create <byte>(), 0);
            var tx1    = new Transaction(0, ImmutableArray.Create(input1), ImmutableArray.Create <TxOutput>(), 0);

            // spend the input
            chain.AddBlock(chainedHeader1);
            utxoBuilder.CalculateUtxo(chain.ToImmutable(), new[] { emptyCoinbaseTx1, tx1 }).ToList();

            // verify utxo storage
            Assert.IsTrue(memoryChainStateCursor.TryGetUnspentTx(txHash, out actualUnspentTx));
            Assert.IsTrue(actualUnspentTx.OutputStates.Length == 3);
            Assert.IsTrue(actualUnspentTx.OutputStates[0] == OutputState.Spent);
            Assert.IsTrue(actualUnspentTx.OutputStates[1] == OutputState.Spent);
            Assert.IsTrue(actualUnspentTx.OutputStates[2] == OutputState.Unspent);

            // create an input to spend the unspent transaction's third output
            var input2 = new TxInput(new TxOutputKey(txHash, txOutputIndex: 2), ImmutableArray.Create <byte>(), 0);
            var tx2    = new Transaction(0, ImmutableArray.Create(input2), ImmutableArray.Create <TxOutput>(), 0);

            // spend the input
            chain.AddBlock(chainedHeader2);
            utxoBuilder.CalculateUtxo(chain.ToImmutable(), new[] { emptyCoinbaseTx2, tx2 }).ToList();

            // verify utxo storage
            Assert.IsFalse(memoryChainStateCursor.ContainsUnspentTx(txHash));
        }