예제 #1
0
        // 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()))}");
            }
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
            }
        }