Beispiel #1
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);
        }
Beispiel #2
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);
        }
Beispiel #3
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);
        }
Beispiel #4
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);
        }
Beispiel #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);
        }
Beispiel #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());
        }
        public void CommitTransaction(ChainBuilder chain, ImmutableSortedDictionary <UInt256, UnspentTx> .Builder unspentTransactions, ImmutableDictionary <int, IImmutableList <SpentTx> > .Builder blockSpentTxes, long chainVersion, long unspentTxesVersion, long blockSpentTxesVersion)
        {
            this.semaphore.Do(() =>
            {
                if (chain != null && this.chainVersion != chainVersion ||
                    unspentTransactions != null && unspentTxesVersion != this.unspentTxesVersion ||
                    blockSpentTxes != null && blockSpentTxesVersion != this.blockSpentTxesVersion)
                {
                    throw new InvalidOperationException();
                }

                if (chain != null)
                {
                    this.chain = chain.ToImmutable().ToBuilder();
                    this.chainVersion++;
                }

                if (unspentTransactions != null)
                {
                    this.unspentTransactions = unspentTransactions.ToImmutable().ToBuilder();
                    this.unspentTxesVersion++;
                }

                if (blockSpentTxes != null)
                {
                    this.blockSpentTxes = blockSpentTxes.ToImmutable().ToBuilder();
                    this.blockSpentTxesVersion++;
                }
            });
        }
Beispiel #8
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
        }
Beispiel #9
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);
            }
        }
Beispiel #10
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));
        }