public static Block <T> MineNextBlock <T>( Block <T> previousBlock, HashAlgorithmGetter hashAlgorithmGetter, PrivateKey miner, IReadOnlyList <Transaction <T> > txs = null, byte[] nonce = null, long difficulty = 1, TimeSpan?blockInterval = null, int protocolVersion = Block <T> .CurrentProtocolVersion, HashDigest <SHA256> stateRootHash = default ) where T : IAction, new() { PreEvaluationBlock <T> preEval = MineNext( previousBlock, hashAlgorithmGetter, txs, nonce, difficulty, miner?.PublicKey, blockInterval, protocolVersion ); return(protocolVersion < 2 ? new Block <T>(preEval, stateRootHash, null) : preEval.Sign(miner, stateRootHash)); }
public override BlockChain <DumbAction> TransferAssetInBlock() { BlockChain <DumbAction> chain = base.TransferAssetInBlock(); DumbAction action = new DumbAction(_addr[0], "a", _addr[0], _addr[0], 1); Transaction <DumbAction> tx = Transaction <DumbAction> .Create( chain.GetNextTxNonce(_addr[0]), _keys[0], chain.Genesis.Hash, new[] { action } ); PreEvaluationBlock <DumbAction> preEval = TestUtils.MineNext( chain.Tip, chain.Policy.GetHashAlgorithm, new[] { tx }, miner: _keys[1].PublicKey, protocolVersion: ProtocolVersion ); chain.Append( new Block <DumbAction>( preEval, preEval.DetermineStateRootHash(chain), signature: null ) ); Assert.Equal( DumbAction.DumbCurrency * 6, chain.GetBalance(_addr[0], DumbAction.DumbCurrency) ); return(chain); }
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(); var timestamp = DateTimeOffset.UtcNow; var txAddress = signer.ToAddress(); var txs = new[] { Transaction <RandomAction> .Create( nonce : 0, privateKey : signer, genesisHash : null, actions : new[] { new RandomAction(txAddress), }), }; var stateStore = new TrieStateStore(new MemoryKeyValueStore()); HashAlgorithmGetter hashAlgorithmGetter = _ => HashAlgorithmType.Of <SHA256>(); PreEvaluationBlock <RandomAction> noStateRootBlock = MineGenesis( hashAlgorithmGetter: hashAlgorithmGetter, miner: GenesisMiner.PublicKey, timestamp: timestamp, transactions: txs ); Block <RandomAction> stateRootBlock = noStateRootBlock.Evaluate(GenesisMiner, null, stateStore); var actionEvaluator = new ActionEvaluator <RandomAction>( hashAlgorithmGetter: hashAlgorithmGetter, policyBlockAction: null, stateGetter: ActionEvaluator <RandomAction> .NullStateGetter, balanceGetter: ActionEvaluator <RandomAction> .NullBalanceGetter, trieGetter: null); var generatedRandomNumbers = new List <int>(); AssertPreEvaluationBlocksEqual(stateRootBlock, noStateRootBlock); for (int i = 0; i < repeatCount; ++i) { var actionEvaluations = actionEvaluator.Evaluate( noStateRootBlock, StateCompleterSet <RandomAction> .Reject); generatedRandomNumbers.Add( (Integer)actionEvaluations[0].OutputStates.GetState(txAddress)); actionEvaluations = actionEvaluator.Evaluate( stateRootBlock, StateCompleterSet <RandomAction> .Reject); generatedRandomNumbers.Add( (Integer)actionEvaluations[0].OutputStates.GetState(txAddress)); } for (int i = 1; i < generatedRandomNumbers.Count; ++i) { Assert.Equal(generatedRandomNumbers[0], generatedRandomNumbers[i]); } }
public void Evaluate() { Address address = _contents.Tx0InBlock1.Signer; var blockAction = new SetStatesAtBlock(address, (Bencodex.Types.Integer) 123, 0); var policy = new BlockPolicy <Arithmetic>( blockAction: blockAction, blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000), minimumDifficulty: 2, difficultyStability: 1 ); var stagePolicy = new VolatileStagePolicy <Arithmetic>(); PreEvaluationBlock <Arithmetic> preEvalGenesis = _contents.Genesis.Mine(policy.GetHashAlgorithm(0)); using (var fx = new DefaultStoreFixture()) { Block <Arithmetic> genesis = preEvalGenesis.Evaluate(_contents.GenesisKey, blockAction, fx.StateStore); AssertPreEvaluationBlocksEqual(preEvalGenesis, genesis); _output.WriteLine("#1: {0}", genesis); var blockChain = new BlockChain <Arithmetic>( policy, stagePolicy, fx.Store, fx.StateStore, genesis ); AssertBencodexEqual((Bencodex.Types.Integer) 123, blockChain.GetState(address)); HashDigest <SHA256> identicalGenesisStateRootHash = preEvalGenesis.DetermineStateRootHash(blockChain); AssertBytesEqual(genesis.StateRootHash, identicalGenesisStateRootHash); BlockContent <Arithmetic> content1 = _contents.Block1; content1.PreviousHash = genesis.Hash; content1.Difficulty = 2; content1.Transactions = new[] { _contents.Tx0InBlock1 }; PreEvaluationBlock <Arithmetic> preEval1 = content1.Mine(policy.GetHashAlgorithm(1)); Block <Arithmetic> block1 = preEval1.Evaluate(_contents.Block1Key, blockChain); AssertPreEvaluationBlocksEqual(preEval1, block1); _output.WriteLine("#1: {0}", block1); HashDigest <SHA256> identicalBlock1StateRootHash = preEval1.DetermineStateRootHash(blockChain); AssertBytesEqual(block1.StateRootHash, identicalBlock1StateRootHash); blockChain.Append(block1); AssertBencodexEqual((Bencodex.Types.Integer) 158, blockChain.GetState(address)); } }
public override void UnsafeConstructor() { BlockContent <Arithmetic> content = _contents.Genesis.Copy(); var preEvalBlock = new PreEvaluationBlock <Arithmetic>(content, _sha256, _validGenesisProof); AssertBlockContentsEqual(content, preEvalBlock); AssertBytesEqual(_validGenesisProof.Nonce, preEvalBlock.Nonce); Assert.Same(_sha256, preEvalBlock.HashAlgorithm); AssertBytesEqual(_validGenesisProof.PreEvaluationHash, preEvalBlock.PreEvaluationHash); content = _contents.Block1.Copy(); preEvalBlock = new PreEvaluationBlock <Arithmetic>(content, _sha256, _validBlock1Proof); AssertBlockContentsEqual(content, preEvalBlock); AssertBytesEqual(_validBlock1Proof.Nonce, preEvalBlock.Nonce); Assert.Same(_sha256, preEvalBlock.HashAlgorithm); AssertBytesEqual(_validBlock1Proof.PreEvaluationHash, preEvalBlock.PreEvaluationHash); Assert.Throws <InvalidBlockNonceException>( () => new PreEvaluationBlock <Arithmetic>(content, _sha256, _invalidBlock1Proof) ); content = _contents.Block1.Copy(); content.PreviousHash = null; Assert.Throws <InvalidBlockPreviousHashException>( () => new PreEvaluationBlock <Arithmetic>(content, _sha256, _validBlock1Proof) ); content = _contents.Genesis.Copy(); content.PreviousHash = _contents.GenesisHash; Assert.Throws <InvalidBlockPreviousHashException>( () => new PreEvaluationBlock <Arithmetic>(content, _sha256, _validGenesisProof) ); content = _contents.Block1.Copy(); content.Difficulty = 0L; Assert.Throws <InvalidBlockDifficultyException>( () => new PreEvaluationBlock <Arithmetic>(content, _sha256, _validBlock1Proof.Nonce) ); content = _contents.Genesis.Copy(); content.Difficulty = 1L; Assert.Throws <InvalidBlockDifficultyException>( () => new PreEvaluationBlock <Arithmetic>(content, _sha256, _validGenesisProof) ); content = _contents.Genesis.Copy(); content.TotalDifficulty = 1; Assert.Throws <InvalidBlockTotalDifficultyException>( () => new PreEvaluationBlock <Arithmetic>(content, _sha256, _validGenesisProof) ); }
public void Constructor() { var contents = new BlockContentFixture(); var random = new System.Random(); var stateRootHash = random.NextHashDigest <SHA256>(); PreEvaluationBlock <Arithmetic> preEval = contents.Genesis.Mine(_fx.GetHashAlgorithm(0)); ImmutableArray <byte> sig = preEval.MakeSignature(contents.GenesisKey, stateRootHash); var block = new Block <Arithmetic>(preEval, stateRootHash, sig); AssertPreEvaluationBlocksEqual(preEval, block); AssertBytesEqual(stateRootHash, block.StateRootHash); AssertBytesEqual(sig, block.Signature); }
public override void SafeConstructorWithPreEvaluationHash() { BlockContent <Arithmetic> content = _contents.Genesis.Copy(); var preEvalBlock = new PreEvaluationBlock <Arithmetic>( content, hashAlgorithm: _sha256, nonce: _validGenesisProof.Nonce, preEvaluationHash: _validGenesisProof.PreEvaluationHash ); AssertBlockContentsEqual(content, preEvalBlock); AssertBytesEqual(_validGenesisProof.Nonce, preEvalBlock.Nonce); Assert.Same(_sha256, preEvalBlock.HashAlgorithm); AssertBytesEqual(_validGenesisProof.PreEvaluationHash, preEvalBlock.PreEvaluationHash); content = _contents.Block1.Copy(); preEvalBlock = new PreEvaluationBlock <Arithmetic>( content, hashAlgorithm: _sha256, nonce: _validBlock1Proof.Nonce, preEvaluationHash: _validBlock1Proof.PreEvaluationHash ); AssertBlockContentsEqual(content, preEvalBlock); AssertBytesEqual(_validBlock1Proof.Nonce, preEvalBlock.Nonce); Assert.Same(_sha256, preEvalBlock.HashAlgorithm); AssertBytesEqual(_validBlock1Proof.PreEvaluationHash, preEvalBlock.PreEvaluationHash); // Mutating the BlockContent<T> instance does not affect PreEvaluatingBlock<T> instance: content.Index++; Assert.Equal(_contents.Block1.Index, preEvalBlock.Index); content = _contents.Block1.Copy(); Assert.Throws <InvalidBlockNonceException>(() => new PreEvaluationBlock <Arithmetic>( content, hashAlgorithm: _sha256, nonce: _invalidBlock1Proof.Nonce, preEvaluationHash: _invalidBlock1Proof.PreEvaluationHash ) ); Assert.Throws <InvalidBlockPreEvaluationHashException>(() => new PreEvaluationBlock <Arithmetic>( content, hashAlgorithm: _sha256, nonce: _validBlock1Proof.Nonce, preEvaluationHash: _invalidBlock1Proof.PreEvaluationHash ) ); }
public void Mine() { var codec = new Codec(); HashAlgorithmType sha256 = HashAlgorithmType.Of <SHA256>(); PreEvaluationBlock <Arithmetic> preEvalBlock = Genesis.Mine(sha256); Assert.True(ByteUtil.Satisfies(preEvalBlock.PreEvaluationHash, Genesis.Difficulty)); AssertBytesEqual( sha256.Digest(codec.Encode(Genesis.MakeCandidateData(preEvalBlock.Nonce))), preEvalBlock.PreEvaluationHash.ToArray() ); HashAlgorithmType sha512 = HashAlgorithmType.Of <SHA512>(); preEvalBlock = Block1.Mine(sha512); Assert.True(ByteUtil.Satisfies(preEvalBlock.PreEvaluationHash, Block1.Difficulty)); AssertBytesEqual( sha512.Digest(codec.Encode(Block1.MakeCandidateData(preEvalBlock.Nonce))), preEvalBlock.PreEvaluationHash.ToArray() ); }
public override void DontCheckPreEvaluationHashWithProtocolVersion0() { // Since PreEvaluationHash comparison between the actual and the expected was not // implemented in ProtocolVersion == 0, we need to maintain this bug on // ProtocolVersion < 1 for backward compatibility: BlockContent <Arithmetic> contentPv0 = _contents.Block1.Copy(); contentPv0.ProtocolVersion = 0; contentPv0.PublicKey = null; contentPv0.Timestamp += TimeSpan.FromSeconds(1); var preEvalBlockPv0 = new PreEvaluationBlock <Arithmetic>( contentPv0, hashAlgorithm: _sha256, nonce: _validBlock1Proof.Nonce, preEvaluationHash: _validBlock1Proof.PreEvaluationHash ); AssertBlockContentsEqual(contentPv0, preEvalBlockPv0); AssertBytesEqual(_validBlock1Proof.Nonce, preEvalBlockPv0.Nonce); Assert.Same(_sha256, preEvalBlockPv0.HashAlgorithm); AssertBytesEqual( _validBlock1Proof.PreEvaluationHash, preEvalBlockPv0.PreEvaluationHash ); // However, such bug must be fixed after ProtocolVersion > 0: BlockContent <Arithmetic> contentPv1 = _contents.Block1.Copy(); contentPv1.PublicKey = null; contentPv1.Timestamp += TimeSpan.FromSeconds(1); Assert.Throws <InvalidBlockPreEvaluationHashException>(() => new PreEvaluationBlock <Arithmetic>( contentPv1, hashAlgorithm: _sha256, nonce: _validBlock1Proof.Nonce, preEvaluationHash: _validBlock1Proof.PreEvaluationHash ) ); }
public static Block <T> MineGenesisBlock <T>( HashAlgorithmGetter hashAlgorithmGetter, PrivateKey miner, IReadOnlyList <Transaction <T> > transactions = null, DateTimeOffset?timestamp = null, int protocolVersion = Block <T> .CurrentProtocolVersion, HashDigest <SHA256> stateRootHash = default ) where T : IAction, new() { PreEvaluationBlock <T> preEval = MineGenesis( hashAlgorithmGetter, miner?.PublicKey, transactions, timestamp, protocolVersion ); return(protocolVersion < 2 ? new Block <T>(preEval, stateRootHash, null) : preEval.Sign(miner, stateRootHash)); }
public static BlockChain <T> MakeBlockChain <T>( IBlockPolicy <T> policy, IStore store, IStateStore stateStore, IEnumerable <T> actions = null, PrivateKey privateKey = null, DateTimeOffset?timestamp = null, IEnumerable <IRenderer <T> > renderers = null, Block <T> genesisBlock = null, int protocolVersion = Block <T> .CurrentProtocolVersion ) where T : IAction, new() { actions = actions ?? ImmutableArray <T> .Empty; privateKey = privateKey ?? ChainPrivateKey; var tx = Transaction <T> .Create( 0, privateKey, null, actions, timestamp : timestamp ?? DateTimeOffset.MinValue); if (genesisBlock is null) { var content = new BlockContent <T>() { Miner = GenesisMiner.ToAddress(), PublicKey = protocolVersion < 2 ? null : GenesisMiner.PublicKey, Timestamp = timestamp ?? DateTimeOffset.MinValue, Transactions = new[] { tx }, ProtocolVersion = protocolVersion, }; var preEval = new PreEvaluationBlock <T>( content, policy.GetHashAlgorithm(0), new Nonce(new byte[] { 0x01, 0x00, 0x00, 0x00 }) ); genesisBlock = protocolVersion < 2 ? new Block <T>( preEval, preEval.DetermineStateRootHash(policy.BlockAction, stateStore), signature: null) : preEval.Evaluate(GenesisMiner, policy.BlockAction, stateStore); } ValidatingActionRenderer <T> validator = null; #pragma warning disable S1121 var chain = new BlockChain <T>( policy, new VolatileStagePolicy <T>(), store, stateStore, genesisBlock, renderers: renderers ?? new[] { validator = new ValidatingActionRenderer <T>() } ); #pragma warning restore S1121 if (validator != null) { validator.BlockChain = chain; } return(chain); }
public void Rebuild( [Option('v', Description = "Print more logs.")] bool verbose, [Option('s', Description = "Path to the chain store.")] string storePath, [Option('c', Description = "Optional chain ID. Default is the canonical chain ID.")] Guid?chainId = null, [Option( 't', Description = "Optional topmost block to execute last. Can be either a block " + "hash or block index. Tip by default.")] string topmost = null, [Option( new char[] { 'f', 'B' }, Description = "Optional bottommost block to execute first. Can be either a " + "block hash or block index. Genesis by default.")] string bottommost = null, [Option('b', Description = "Bypass the state root hash check.")] bool bypassStateRootHashCheck = false, [Option( 'm', Description = "Use the in-memory key-value state store and dump it to " + "the specified directory path in the end.", ValueName = "DIR")] string useMemoryKvStore = null ) { using Logger logger = Utils.ConfigureLogger(verbose); CancellationToken cancellationToken = GetInterruptSignalCancellationToken(); TextWriter stderr = Console.Error; ( BlockChain <NCAction> chain, IStore store, IKeyValueStore stateKvStore, IStateStore stateStore ) = Utils.GetBlockChain( logger, storePath, chainId, useMemoryKvStore is string p ? new MemoryKeyValueStore(p, stderr) : null ); Block <NCAction> bottom = Utils.ParseBlockOffset(chain, bottommost, 0); Block <NCAction> top = Utils.ParseBlockOffset(chain, topmost); stderr.WriteLine("It will execute all actions (tx actions & block actions)"); stderr.WriteLine( " ...from the block #{0} {1}", bottom.Index.ToString(CultureInfo.InvariantCulture).PadRight( top.Index.ToString(CultureInfo.InvariantCulture).Length), bottom.Hash); stderr.WriteLine(" ...to the block #{0} {1}.", top.Index, top.Hash); IBlockPolicy <NCAction> policy = chain.Policy; (Block <NCAction>, string)? invalidStateRootHashBlock = null; long totalBlocks = top.Index - bottom.Index + 1; long blocksExecuted = 0L; long txsExecuted = 0L; DateTimeOffset started = DateTimeOffset.Now; IEnumerable <BlockHash> blockHashes = store.IterateIndexes( chain.Id, (int)bottom.Index, (int)(top.Index - bottom.Index + 1L) ); foreach (BlockHash blockHash in blockHashes) { if (cancellationToken.IsCancellationRequested) { throw new CommandExitedException(1); } Block <NCAction> block = store.GetBlock <NCAction>(policy.GetHashAlgorithm, blockHash); var preEvalBlock = new PreEvaluationBlock <NCAction>( block, block.HashAlgorithm, block.Nonce, block.PreEvaluationHash ); stderr.WriteLine( "[{0}/{1}] Executing block #{2} {3}...", block.Index - bottom.Index + 1L, top.Index - bottom.Index + 1L, block.Index, block.Hash ); IImmutableDictionary <string, IValue> delta; HashDigest <SHA256> stateRootHash = block.Index < 1 ? preEvalBlock.DetermineStateRootHash(chain.Policy.BlockAction, stateStore, out delta) : preEvalBlock.DetermineStateRootHash( chain, StateCompleterSet <NCAction> .Reject, out delta); DateTimeOffset now = DateTimeOffset.Now; if (invalidStateRootHashBlock is null && !stateRootHash.Equals(block.StateRootHash)) { string blockDump = DumpBencodexToFile( block.MarshalBlock(), $"block_{block.Index}_{block.Hash}" ); string deltaDump = DumpBencodexToFile( new Dictionary( delta.Select(kv => new KeyValuePair <IKey, IValue>(new Text(kv.Key), kv.Value))), $"delta_{block.Index}_{block.Hash}" ); string message = $"Unexpected state root hash for block #{block.Index} {block.Hash}.\n" + $" Expected: {block.StateRootHash}\n Actual: {stateRootHash}\n" + $" Block file: {blockDump}\n Evaluated delta file: {deltaDump}\n"; if (!bypassStateRootHashCheck) { throw new CommandExitedException(message, 1); } stderr.WriteLine(message); invalidStateRootHashBlock = (block, message); } blocksExecuted++; txsExecuted += block.Transactions.Count; TimeSpan elapsed = now - started; if (blocksExecuted >= totalBlocks || block.Hash.Equals(top.Hash)) { stderr.WriteLine("Elapsed: {0:c}.", elapsed); break; } else { TimeSpan estimatedRemaining = elapsed / blocksExecuted * (totalBlocks - blocksExecuted); stderr.WriteLine( "Elapsed: {0:c}, estimated remaining: {1:c}.", elapsed, estimatedRemaining ); } } if (invalidStateRootHashBlock is { } b) { stderr.WriteLine( "Note that the state root hash check is bypassed, " + "but there was an invalid state root hash for block #{0} {1}. {2}", b.Item1.Index, b.Item1.Hash, b.Item2 ); } TimeSpan totalElapsed = DateTimeOffset.Now - started; stderr.WriteLine("Total elapsed: {0:c}", totalElapsed); stderr.WriteLine("Avg block execution time: {0:c}", totalElapsed / totalBlocks); stderr.WriteLine("Avg tx execution time: {0:c}", totalElapsed / txsExecuted); stateKvStore.Dispose(); stateStore.Dispose(); }