public void Idempotent() { // NOTE: This test checks that blocks can be evaluated idempotently. Also it checks // the action results in pre-evaluation step and in evaluation step are equal. const int repeatCount = 2; var signer = new PrivateKey(); Address address = signer.ToAddress(); var timestamp = DateTimeOffset.UtcNow; var txs = new[] { Transaction <RandomAction> .Create( 0, signer, null, new[] { new RandomAction(address), }), }; var stateStore = new TrieStateStore(new MemoryKeyValueStore(), new MemoryKeyValueStore()); Block <RandomAction> noStateRootBlock = TestUtils.MineGenesis( timestamp: timestamp, transactions: txs); Block <RandomAction> stateRootBlock = TestUtils.MineGenesis( timestamp: timestamp, transactions: txs).AttachStateRootHash(stateStore, null); var blockEvaluator = new BlockEvaluator <RandomAction>(null, NullStateGetter, NullBalanceGetter, null); var generatedRandomNumbers = new List <int>(); Assert.NotEqual(stateRootBlock.Hash, noStateRootBlock.Hash); Assert.Equal(stateRootBlock.PreEvaluationHash, noStateRootBlock.PreEvaluationHash); for (int i = 0; i < repeatCount; ++i) { var actionEvaluations = blockEvaluator.EvaluateActions( noStateRootBlock, StateCompleterSet <RandomAction> .Reject); generatedRandomNumbers.Add( (Integer)actionEvaluations[0].OutputStates.GetState(address)); actionEvaluations = blockEvaluator.EvaluateActions( stateRootBlock, StateCompleterSet <RandomAction> .Reject); generatedRandomNumbers.Add( (Integer)actionEvaluations[0].OutputStates.GetState(address)); } for (int i = 1; i < generatedRandomNumbers.Count; ++i) { Assert.Equal(generatedRandomNumbers[0], generatedRandomNumbers[i]); } }
public static Block <T> MineGenesis <T>( Address?miner = null, IEnumerable <Transaction <T> > transactions = null, DateTimeOffset?timestamp = null, IAction blockAction = null, bool checkStateRootHash = false ) where T : IAction, new() { if (transactions is null) { transactions = new List <Transaction <T> >(); } var block = new Block <T>( index: 0, difficulty: 0, totalDifficulty: 0, nonce: new Nonce(new byte[] { 0x01, 0x00, 0x00, 0x00 }), miner: miner ?? GenesisMinerAddress, previousHash: null, timestamp: timestamp ?? new DateTimeOffset(2018, 11, 29, 0, 0, 0, TimeSpan.Zero), transactions: transactions ); if (checkStateRootHash) { var blockEvaluator = new BlockEvaluator <T>( blockAction, (address, digest, arg3) => null, (address, currency, arg3, arg4) => new FungibleAssetValue(currency)); var actionEvaluationResult = blockEvaluator .EvaluateActions(block, StateCompleterSet <T> .Reject) .GetTotalDelta(BlockChain <T> .ToStateKey, BlockChain <T> .ToFungibleAssetKey); var trie = new MerkleTrie(new DefaultKeyValueStore(null)); foreach (var pair in actionEvaluationResult) { trie.Set(Encoding.UTF8.GetBytes(pair.Key), pair.Value); } var stateRootHash = trie.Commit(rehearsal: true).Hash; block = new Block <T>(block, stateRootHash); } return(block); }
public static Block <T> AttachStateRootHash <T>( this Block <T> block, IStateStore stateStore, IAction blockAction) where T : IAction, new() { IValue StateGetter( Address address, HashDigest <SHA256>?blockHash, StateCompleter <T> stateCompleter) => blockHash is null ? null : stateStore.GetState(ToStateKey(address), blockHash.Value); FungibleAssetValue FungibleAssetValueGetter( Address address, Currency currency, HashDigest <SHA256>?blockHash, FungibleAssetStateCompleter <T> stateCompleter) { if (blockHash is null) { return(FungibleAssetValue.FromRawValue(currency, 0)); } IValue value = stateStore.GetState( ToFungibleAssetKey(address, currency), blockHash.Value); return(FungibleAssetValue.FromRawValue( currency, value is Bencodex.Types.Integer i ? i.Value : 0)); } var blockEvaluator = new BlockEvaluator <T>( blockAction, StateGetter, FungibleAssetValueGetter, null); var actionEvaluationResult = blockEvaluator .EvaluateActions(block, StateCompleterSet <T> .Reject) .GetTotalDelta(ToStateKey, ToFungibleAssetKey); stateStore.SetStates(block, actionEvaluationResult); if (stateStore is TrieStateStore trieStateStore) { block = new Block <T>(block, trieStateStore.GetRootHash(block.Hash)); stateStore.SetStates(block, actionEvaluationResult); } return(block); }