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); }
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); }
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); }
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); }
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); }
/// <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 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)); }
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); }
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 }
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); }
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); } }
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); }
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); }
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)); }
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)); }