public void TestCacheCoinView() { using (NodeContext ctx = NodeContext.Create(this)) { Block genesis = ctx.Network.GetGenesis(); var genesisChainedHeader = new ChainedHeader(genesis.Header, ctx.Network.GenesisHash, 0); ChainedHeader chained = this.MakeNext(genesisChainedHeader, ctx.Network); var dateTimeProvider = new DateTimeProvider(); var cacheCoinView = new CachedCoinView(this.network, new Checkpoints(), ctx.Coindb, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, NodeSettings.Default(this.network), new Mock <IVersionProvider>().Object), new ConsensusSettings(new NodeSettings(this.network))); cacheCoinView.SaveChanges(new UnspentOutput[] { new UnspentOutput(new OutPoint(genesis.Transactions[0], 0), new Coins(0, genesis.Transactions[0].Outputs.First(), true)) }, new HashHeightPair(genesisChainedHeader), new HashHeightPair(chained)); Assert.NotNull(cacheCoinView.FetchCoins(new[] { new OutPoint(genesis.Transactions[0], 0) }).UnspentOutputs.Values.FirstOrDefault().Coins); Assert.Null(cacheCoinView.FetchCoins(new[] { new OutPoint() }).UnspentOutputs.Values.FirstOrDefault().Coins); Assert.Equal(new HashHeightPair(chained), cacheCoinView.GetTipHash()); Assert.Null(ctx.Coindb.FetchCoins(new[] { new OutPoint(genesis.Transactions[0], 0) }).UnspentOutputs.Values.FirstOrDefault().Coins); Assert.Equal(chained.Previous.HashBlock, ctx.Coindb.GetTipHash().Hash); cacheCoinView.Flush(); Assert.NotNull(ctx.Coindb.FetchCoins(new[] { new OutPoint(genesis.Transactions[0], 0) }).UnspentOutputs.Values.FirstOrDefault().Coins); Assert.Equal(chained.HashBlock, ctx.Coindb.GetTipHash().Hash); //Assert.Null(ctx.PersistentCoinView.FetchCoinsAsync(new[] { new uint256() }).Result.UnspentOutputs[0]); //var previous = chained; //chained = MakeNext(MakeNext(genesisChainedBlock)); //chained = MakeNext(MakeNext(genesisChainedBlock)); //ctx.PersistentCoinView.SaveChangesAsync(new UnspentOutputs[0], previous.HashBlock, chained.HashBlock).Wait(); //Assert.Equal(chained.HashBlock, ctx.PersistentCoinView.GetTipHashAsync().GetAwaiter().GetResult()); //ctx.ReloadPersistentCoinView(); //Assert.Equal(chained.HashBlock, ctx.PersistentCoinView.GetTipHashAsync().GetAwaiter().GetResult()); //Assert.NotNull(ctx.PersistentCoinView.FetchCoinsAsync(new[] { genesis.Transactions[0].GetHash() }).Result.UnspentOutputs[0]); //Assert.Null(ctx.PersistentCoinView.FetchCoinsAsync(new[] { new uint256() }).Result.UnspentOutputs[0]); } }
public void TestCacheCoinView() { using (NodeContext ctx = NodeContext.Create(this)) { Block genesis = ctx.Network.GetGenesis(); var genesisChainedHeader = new ChainedHeader(genesis.Header, ctx.Network.GenesisHash, 0); ChainedHeader chained = this.MakeNext(genesisChainedHeader, ctx.Network); var dateTimeProvider = new DateTimeProvider(); var cacheCoinView = new CachedCoinView(ctx.PersistentCoinView, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider)); cacheCoinView.SaveChanges(new UnspentOutputs[] { new UnspentOutputs(genesis.Transactions[0].GetHash(), new Coins(genesis.Transactions[0], 0)) }, null, genesisChainedHeader.HashBlock, chained.HashBlock, chained.Height); Assert.NotNull(cacheCoinView.FetchCoins(new[] { genesis.Transactions[0].GetHash() }).UnspentOutputs[0]); Assert.Null(cacheCoinView.FetchCoins(new[] { new uint256() }).UnspentOutputs[0]); Assert.Equal(chained.HashBlock, cacheCoinView.GetTipHash()); Assert.Null(ctx.PersistentCoinView.FetchCoins(new[] { genesis.Transactions[0].GetHash() }).UnspentOutputs[0]); Assert.Equal(chained.Previous.HashBlock, ctx.PersistentCoinView.GetTipHash()); cacheCoinView.Flush(); Assert.NotNull(ctx.PersistentCoinView.FetchCoins(new[] { genesis.Transactions[0].GetHash() }).UnspentOutputs[0]); Assert.Equal(chained.HashBlock, ctx.PersistentCoinView.GetTipHash()); //Assert.Null(ctx.PersistentCoinView.FetchCoinsAsync(new[] { new uint256() }).Result.UnspentOutputs[0]); //var previous = chained; //chained = MakeNext(MakeNext(genesisChainedBlock)); //chained = MakeNext(MakeNext(genesisChainedBlock)); //ctx.PersistentCoinView.SaveChangesAsync(new UnspentOutputs[0], previous.HashBlock, chained.HashBlock).Wait(); //Assert.Equal(chained.HashBlock, ctx.PersistentCoinView.GetTipHashAsync().GetAwaiter().GetResult()); //ctx.ReloadPersistentCoinView(); //Assert.Equal(chained.HashBlock, ctx.PersistentCoinView.GetTipHashAsync().GetAwaiter().GetResult()); //Assert.NotNull(ctx.PersistentCoinView.FetchCoinsAsync(new[] { genesis.Transactions[0].GetHash() }).Result.UnspentOutputs[0]); //Assert.Null(ctx.PersistentCoinView.FetchCoinsAsync(new[] { new uint256() }).Result.UnspentOutputs[0]); } }
public void CanRewind() { using (NodeContext nodeContext = NodeContext.Create(this)) { var dateTimeProvider = new DateTimeProvider(); var cacheCoinView = new CachedCoinView(this.network, new Checkpoints(), nodeContext.Coindb, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, NodeSettings.Default(this.network), new Mock <IVersionProvider>().Object), new ConsensusSettings(new NodeSettings(this.network))); var tester = new CoinViewTester(cacheCoinView); List <(Coins, OutPoint)> coinsA = tester.CreateCoins(5); List <(Coins, OutPoint)> coinsB = tester.CreateCoins(1); tester.NewBlock(); cacheCoinView.Flush(); Assert.True(tester.Exists(coinsA[2])); Assert.True(tester.Exists(coinsB[0])); // Spend some coins. tester.Spend(coinsA[2]); tester.Spend(coinsB[0]); tester.NewBlock(); // This will save an empty RewindData instance tester.NewBlock(); // Create a new coin set/ List <(Coins, OutPoint)> coinsC = tester.CreateCoins(1); tester.NewBlock(); Assert.True(tester.Exists(coinsA[0])); Assert.True(tester.Exists(coinsC[0])); Assert.False(tester.Exists(coinsA[2])); Assert.False(tester.Exists(coinsB[0])); // We need to rewind 3 times as we are now rewinding one block at a time. tester.Rewind(); // coinsC[0] should not exist any more. tester.Rewind(); // coinsA[2] should be spendable again. tester.Rewind(); // coinsB[2] should be spendable again. Assert.False(tester.Exists(coinsC[0])); Assert.True(tester.Exists(coinsA[2])); Assert.True(tester.Exists(coinsB[0])); // Spend some coins and esnure they are not spendable. tester.Spend(coinsA[2]); tester.Spend(coinsB[0]); tester.NewBlock(); cacheCoinView.Flush(); Assert.False(tester.Exists(coinsA[2])); Assert.False(tester.Exists(coinsB[0])); // Rewind so that coinsA[2] and coinsB[0] become spendable again. tester.Rewind(); Assert.True(tester.Exists(coinsA[2])); Assert.True(tester.Exists(coinsB[0])); // Create 7 coins in a new coin set and spend the first coin. List <(Coins, OutPoint)> coinsD = tester.CreateCoins(7); tester.Spend(coinsD[0]); // Create a coin in a new coin set and spend it. List <(Coins, OutPoint)> coinsE = tester.CreateCoins(1); tester.Spend(coinsE[0]); tester.NewBlock(); Assert.True(tester.Exists(coinsD[1])); Assert.False(tester.Exists(coinsD[0])); cacheCoinView.Flush(); // Creates another empty RewindData instance. tester.NewBlock(); // Rewind one block. tester.Rewind(); // coinsD[1] was never touched, so should remain unchanged. // coinsD[0] was spent but the block in which the changes happened was not yet rewound to, so it remains unchanged. // coinsE[0] was spent but the block in which the changes happened was not yet rewound to, so it remains unchanged. // coinsA[1] was not touched, so should remain unchanged. // coinsB[1] was not touched, so should remain unchanged. Assert.True(tester.Exists(coinsD[1])); Assert.False(tester.Exists(coinsD[0])); Assert.False(tester.Exists(coinsE[0])); Assert.True(tester.Exists(coinsA[2])); Assert.True(tester.Exists(coinsB[0])); // Rewind one block. tester.Rewind(); // coinsD[0] should now not exist in CoinView anymore. // coinsE[0] should now not exist in CoinView anymore. Assert.False(tester.Exists(coinsD[0])); Assert.False(tester.Exists(coinsE[0])); } }