// After sufficient votes are on the emulated stateHash, the block is approved and // executed to add to the chain public void ProduceBlock(IEnumerable <TransactionReceipt> receipts, BlockHeader header, MultiSig multiSig) { Logger.LogDebug($"Producing block {header.Index}"); if (_blockManager.GetHeight() >= header.Index) { Logger.LogWarning("Block already produced"); return; } var blockWithTransactions = new BlockBuilder(_blockManager.LatestBlock().Header, header.StateHash) .WithTransactions(receipts) .WithMultisig(multiSig) .Build(header.Nonce); Logger.LogDebug($"Block approved by consensus: {blockWithTransactions.Block.Hash.ToHex()}"); if (_blockManager.GetHeight() + 1 != header.Index) { throw new InvalidOperationException( $"Current height is {_blockManager.GetHeight()}, but we are trying to produce block {header.Index}" ); } var result = _blockManager.Execute( blockWithTransactions.Block, blockWithTransactions.Transactions, commit: true, checkStateHash: true); if (result != OperatingError.Ok) { Logger.LogError( $"Block {blockWithTransactions.Block.Header.Index} ({blockWithTransactions.Block.Hash.ToHex()}) was not persisted: {result}" ); Logger.LogTrace($"Block raw data: {blockWithTransactions.Block.ToByteArray().ToHex()}"); Logger.LogTrace($"Block transactions data: {string.Join(", ", blockWithTransactions.Transactions.Select(tx => tx.ToByteArray().ToHex()))}"); } }
private OperatingError ExecuteBlock(Block block, TransactionReceipt[]?receipts = null) { receipts ??= new TransactionReceipt[] { }; var(_, _, stateHash, _) = _blockManager.Emulate(block, receipts); var height = _stateManager.LastApprovedSnapshot.Blocks.GetTotalBlockHeight(); var predecessor = _stateManager.LastApprovedSnapshot.Blocks.GetBlockByHeight(height); var(header, multisig) = BuildHeaderAndMultisig(block.Header.MerkleRoot, predecessor, stateHash); block.Header = header; block.Multisig = multisig; block.Hash = header.Keccak(); var status = _blockManager.Execute(block, receipts, true, true); return(status); }
public bool HandleBlockFromPeer(BlockInfo blockWithTransactions, ECDSAPublicKey publicKey) { Logger.LogTrace("HandleBlockFromPeer"); lock (_blocksLock) { var block = blockWithTransactions.Block; var receipts = blockWithTransactions.Transactions; Logger.LogDebug( $"Got block {block.Header.Index} with hash {block.Hash.ToHex()} from peer {publicKey.ToHex()}"); var myHeight = _blockManager.GetHeight(); if (block.Header.Index != myHeight + 1) { Logger.LogTrace( $"Skipped block {block.Header.Index} from peer {publicKey.ToHex()}: our height is {myHeight}"); return(false); } if (!block.TransactionHashes.ToHashSet().SetEquals(receipts.Select(r => r.Hash))) { try { var needHashes = string.Join(", ", block.TransactionHashes.Select(x => x.ToHex())); var gotHashes = string.Join(", ", receipts.Select(x => x.Hash.ToHex())); Logger.LogTrace( $"Skipped block {block.Header.Index} from peer {publicKey.ToHex()}: expected hashes [{needHashes}] got hashes [{gotHashes}]"); } catch (Exception e) { Logger.LogWarning($"Failed to get transaction receipts for tx hash: {e}"); } return(false); } var error = _blockManager.VerifySignatures(block, true); if (error != OperatingError.Ok) { Logger.LogTrace($"Skipped block {block.Header.Index} from peer {publicKey.ToHex()}: invalid multisig with error: {error}"); return(false); } // This is to tell consensus manager to terminate current era, since we trust given multisig OnSignedBlockReceived?.Invoke(this, block.Header.Index); error = _stateManager.SafeContext(() => { if (_blockManager.GetHeight() + 1 == block.Header.Index) { return(_blockManager.Execute(block, receipts, commit: true, checkStateHash: true)); } Logger.LogTrace( $"We have blockchain with height {_blockManager.GetHeight()} but got block {block.Header.Index}"); return(OperatingError.BlockAlreadyExists); }); if (error == OperatingError.BlockAlreadyExists) { Logger.LogTrace( $"Skipped block {block.Header.Index} from peer {publicKey.ToHex()}: block already exists"); return(true); } if (error != OperatingError.Ok) { Logger.LogWarning( $"Unable to persist block {block.Header.Index} (current height {_blockManager.GetHeight()}), got error {error}, dropping peer"); return(false); } lock (_peerHasBlocks) Monitor.PulseAll(_peerHasBlocks); return(true); } }