From 6b04e739870fc092a1e61830a09f68c3d4b2a033 Mon Sep 17 00:00:00 2001 From: AlexSSD7 Date: Fri, 12 Feb 2021 21:57:28 +0100 Subject: [PATCH 01/16] Move serialization functions to a different package --- eth/api.go | 4 +- internal/ethapi/api.go | 187 +++--------------------- internal/serialization/serialization.go | 168 +++++++++++++++++++++ 3 files changed, 193 insertions(+), 166 deletions(-) create mode 100644 internal/serialization/serialization.go diff --git a/eth/api.go b/eth/api.go index 53ef91392ba6..fbfa1e42acba 100644 --- a/eth/api.go +++ b/eth/api.go @@ -34,7 +34,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/internal/serialization" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" @@ -346,7 +346,7 @@ func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, } else { blockRlp = fmt.Sprintf("0x%x", rlpBytes) } - if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true); err != nil { + if blockJSON, err = serialization.RPCMarshalBlock(block, true, true); err != nil { blockJSON = map[string]interface{}{"error": err.Error()} } results = append(results, &BadBlockArgs{ diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 9c3f6b91616f..6d2c2ff5f79d 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -39,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/serialization" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" @@ -99,26 +100,26 @@ func NewPublicTxPoolAPI(b Backend) *PublicTxPoolAPI { } // Content returns the transactions contained within the transaction pool. -func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { - content := map[string]map[string]map[string]*RPCTransaction{ - "pending": make(map[string]map[string]*RPCTransaction), - "queued": make(map[string]map[string]*RPCTransaction), +func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*serialization.RPCTransaction { + content := map[string]map[string]map[string]*serialization.RPCTransaction{ + "pending": make(map[string]map[string]*serialization.RPCTransaction), + "queued": make(map[string]map[string]*serialization.RPCTransaction), } pending, queue := s.b.TxPoolContent() // Flatten the pending transactions for account, txs := range pending { - dump := make(map[string]*RPCTransaction) + dump := make(map[string]*serialization.RPCTransaction) for _, tx := range txs { - dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx) + dump[fmt.Sprintf("%d", tx.Nonce())] = serialization.NewRPCPendingTransaction(tx) } content["pending"][account.Hex()] = dump } // Flatten the queued transactions for account, txs := range queue { - dump := make(map[string]*RPCTransaction) + dump := make(map[string]*serialization.RPCTransaction) for _, tx := range txs { - dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx) + dump[fmt.Sprintf("%d", tx.Nonce())] = serialization.NewRPCPendingTransaction(tx) } content["queued"][account.Hex()] = dump } @@ -1118,69 +1119,10 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes { return formatted } -// RPCMarshalHeader converts the given header to the RPC output . -func RPCMarshalHeader(head *types.Header) map[string]interface{} { - return map[string]interface{}{ - "number": (*hexutil.Big)(head.Number), - "hash": head.Hash(), - "parentHash": head.ParentHash, - "nonce": head.Nonce, - "mixHash": head.MixDigest, - "sha3Uncles": head.UncleHash, - "logsBloom": head.Bloom, - "stateRoot": head.Root, - "miner": head.Coinbase, - "difficulty": (*hexutil.Big)(head.Difficulty), - "extraData": hexutil.Bytes(head.Extra), - "size": hexutil.Uint64(head.Size()), - "gasLimit": hexutil.Uint64(head.GasLimit), - "gasUsed": hexutil.Uint64(head.GasUsed), - "timestamp": hexutil.Uint64(head.Time), - "transactionsRoot": head.TxHash, - "receiptsRoot": head.ReceiptHash, - } -} - -// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are -// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain -// transaction hashes. -func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields := RPCMarshalHeader(block.Header()) - fields["size"] = hexutil.Uint64(block.Size()) - - if inclTx { - formatTx := func(tx *types.Transaction) (interface{}, error) { - return tx.Hash(), nil - } - if fullTx { - formatTx = func(tx *types.Transaction) (interface{}, error) { - return newRPCTransactionFromBlockHash(block, tx.Hash()), nil - } - } - txs := block.Transactions() - transactions := make([]interface{}, len(txs)) - var err error - for i, tx := range txs { - if transactions[i], err = formatTx(tx); err != nil { - return nil, err - } - } - fields["transactions"] = transactions - } - uncles := block.Uncles() - uncleHashes := make([]common.Hash, len(uncles)) - for i, uncle := range uncles { - uncleHashes[i] = uncle.Hash() - } - fields["uncles"] = uncleHashes - - return fields, nil -} - // rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires // a `PublicBlockchainAPI`. func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} { - fields := RPCMarshalHeader(header) + fields := serialization.RPCMarshalHeader(header) fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, header.Hash())) return fields } @@ -1188,7 +1130,7 @@ func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *type // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires // a `PublicBlockchainAPI`. func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields, err := RPCMarshalBlock(b, inclTx, fullTx) + fields, err := serialization.RPCMarshalBlock(b, inclTx, fullTx) if err != nil { return nil, err } @@ -1198,89 +1140,6 @@ func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Bloc return fields, err } -// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction -type RPCTransaction struct { - BlockHash *common.Hash `json:"blockHash"` - BlockNumber *hexutil.Big `json:"blockNumber"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - Hash common.Hash `json:"hash"` - Input hexutil.Bytes `json:"input"` - Nonce hexutil.Uint64 `json:"nonce"` - To *common.Address `json:"to"` - TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` - Value *hexutil.Big `json:"value"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` -} - -// newRPCTransaction returns a transaction that will serialize to the RPC -// representation, with the given location metadata set (if available). -func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction { - var signer types.Signer = types.FrontierSigner{} - if tx.Protected() { - signer = types.NewEIP155Signer(tx.ChainId()) - } - from, _ := types.Sender(signer, tx) - v, r, s := tx.RawSignatureValues() - - result := &RPCTransaction{ - From: from, - Gas: hexutil.Uint64(tx.Gas()), - GasPrice: (*hexutil.Big)(tx.GasPrice()), - Hash: tx.Hash(), - Input: hexutil.Bytes(tx.Data()), - Nonce: hexutil.Uint64(tx.Nonce()), - To: tx.To(), - Value: (*hexutil.Big)(tx.Value()), - V: (*hexutil.Big)(v), - R: (*hexutil.Big)(r), - S: (*hexutil.Big)(s), - } - if blockHash != (common.Hash{}) { - result.BlockHash = &blockHash - result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) - result.TransactionIndex = (*hexutil.Uint64)(&index) - } - return result -} - -// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation -func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction { - return newRPCTransaction(tx, common.Hash{}, 0, 0) -} - -// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction { - txs := b.Transactions() - if index >= uint64(len(txs)) { - return nil - } - return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index) -} - -// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. -func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes { - txs := b.Transactions() - if index >= uint64(len(txs)) { - return nil - } - blob, _ := rlp.EncodeToBytes(txs[index]) - return blob -} - -// newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction { - for idx, tx := range b.Transactions() { - if tx.Hash() == hash { - return newRPCTransactionFromBlockIndex(b, uint64(idx)) - } - } - return nil -} - // PublicTransactionPoolAPI exposes methods for the RPC interface type PublicTransactionPoolAPI struct { b Backend @@ -1311,17 +1170,17 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Co } // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. -func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { +func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *serialization.RPCTransaction { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index)) + return serialization.NewRPCTransactionFromBlockIndex(block, uint64(index)) } return nil } // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. -func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { +func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *serialization.RPCTransaction { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index)) + return serialization.NewRPCTransactionFromBlockIndex(block, uint64(index)) } return nil } @@ -1329,7 +1188,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return newRPCRawTransactionFromBlockIndex(block, uint64(index)) + return serialization.NewRPCRawTransactionFromBlockIndex(block, uint64(index)) } return nil } @@ -1337,7 +1196,7 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx co // GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { - return newRPCRawTransactionFromBlockIndex(block, uint64(index)) + return serialization.NewRPCRawTransactionFromBlockIndex(block, uint64(index)) } return nil } @@ -1362,18 +1221,18 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr } // GetTransactionByHash returns the transaction for the given hash -func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { +func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*serialization.RPCTransaction, error) { // Try to return an already finalized transaction tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) if err != nil { return nil, err } if tx != nil { - return newRPCTransaction(tx, blockHash, blockNumber, index), nil + return serialization.NewRPCTransaction(tx, blockHash, blockNumber, index), nil } // No finalized transaction, try to retrieve it from the pool if tx := s.b.GetPoolTransaction(hash); tx != nil { - return newRPCPendingTransaction(tx), nil + return serialization.NewRPCPendingTransaction(tx), nil } // Transaction unknown, return as such @@ -1696,7 +1555,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen // PendingTransactions returns the transactions that are in the transaction pool // and have a from address that is one of the accounts this node manages. -func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) { +func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*serialization.RPCTransaction, error) { pending, err := s.b.GetPoolTransactions() if err != nil { return nil, err @@ -1707,7 +1566,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err accounts[account.Address] = struct{}{} } } - transactions := make([]*RPCTransaction, 0, len(pending)) + transactions := make([]*serialization.RPCTransaction, 0, len(pending)) for _, tx := range pending { var signer types.Signer = types.HomesteadSigner{} if tx.Protected() { @@ -1715,7 +1574,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err } from, _ := types.Sender(signer, tx) if _, exists := accounts[from]; exists { - transactions = append(transactions, newRPCPendingTransaction(tx)) + transactions = append(transactions, serialization.NewRPCPendingTransaction(tx)) } } return transactions, nil diff --git a/internal/serialization/serialization.go b/internal/serialization/serialization.go new file mode 100644 index 000000000000..464af310a5f7 --- /dev/null +++ b/internal/serialization/serialization.go @@ -0,0 +1,168 @@ +// Copyright 2021 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package serialization + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" +) + +// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction +type RPCTransaction struct { + BlockHash *common.Hash `json:"blockHash"` + BlockNumber *hexutil.Big `json:"blockNumber"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + Hash common.Hash `json:"hash"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` +} + +// NewRPCTransaction returns a transaction that will serialize to the RPC +// representation, with the given location metadata set (if available). +func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction { + var signer types.Signer = types.FrontierSigner{} + if tx.Protected() { + signer = types.NewEIP155Signer(tx.ChainId()) + } + from, _ := types.Sender(signer, tx) + v, r, s := tx.RawSignatureValues() + + result := &RPCTransaction{ + From: from, + Gas: hexutil.Uint64(tx.Gas()), + GasPrice: (*hexutil.Big)(tx.GasPrice()), + Hash: tx.Hash(), + Input: hexutil.Bytes(tx.Data()), + Nonce: hexutil.Uint64(tx.Nonce()), + To: tx.To(), + Value: (*hexutil.Big)(tx.Value()), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), + } + if blockHash != (common.Hash{}) { + result.BlockHash = &blockHash + result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) + result.TransactionIndex = (*hexutil.Uint64)(&index) + } + return result +} + +// NewRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation +func NewRPCPendingTransaction(tx *types.Transaction) *RPCTransaction { + return NewRPCTransaction(tx, common.Hash{}, 0, 0) +} + +// NewRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. +func NewRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction { + txs := b.Transactions() + if index >= uint64(len(txs)) { + return nil + } + return NewRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index) +} + +// NewRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. +func NewRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes { + txs := b.Transactions() + if index >= uint64(len(txs)) { + return nil + } + blob, _ := rlp.EncodeToBytes(txs[index]) + return blob +} + +// NewRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. +func NewRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction { + for idx, tx := range b.Transactions() { + if tx.Hash() == hash { + return NewRPCTransactionFromBlockIndex(b, uint64(idx)) + } + } + return nil +} + +// RPCMarshalHeader converts the given header to the RPC output . +func RPCMarshalHeader(head *types.Header) map[string]interface{} { + return map[string]interface{}{ + "number": (*hexutil.Big)(head.Number), + "hash": head.Hash(), + "parentHash": head.ParentHash, + "nonce": head.Nonce, + "mixHash": head.MixDigest, + "sha3Uncles": head.UncleHash, + "logsBloom": head.Bloom, + "stateRoot": head.Root, + "miner": head.Coinbase, + "difficulty": (*hexutil.Big)(head.Difficulty), + "extraData": hexutil.Bytes(head.Extra), + "size": hexutil.Uint64(head.Size()), + "gasLimit": hexutil.Uint64(head.GasLimit), + "gasUsed": hexutil.Uint64(head.GasUsed), + "timestamp": hexutil.Uint64(head.Time), + "transactionsRoot": head.TxHash, + "receiptsRoot": head.ReceiptHash, + } +} + +// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are +// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain +// transaction hashes. +func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { + fields := RPCMarshalHeader(block.Header()) + fields["size"] = hexutil.Uint64(block.Size()) + + if inclTx { + formatTx := func(tx *types.Transaction) (interface{}, error) { + return tx.Hash(), nil + } + if fullTx { + formatTx = func(tx *types.Transaction) (interface{}, error) { + return NewRPCTransactionFromBlockHash(block, tx.Hash()), nil + } + } + txs := block.Transactions() + transactions := make([]interface{}, len(txs)) + var err error + for i, tx := range txs { + if transactions[i], err = formatTx(tx); err != nil { + return nil, err + } + } + fields["transactions"] = transactions + } + uncles := block.Uncles() + uncleHashes := make([]common.Hash, len(uncles)) + for i, uncle := range uncles { + uncleHashes[i] = uncle.Hash() + } + fields["uncles"] = uncleHashes + + return fields, nil +} From be505ac103278299a30b698517f52b7d5d01adfb Mon Sep 17 00:00:00 2001 From: AlexSSD7 Date: Fri, 12 Feb 2021 21:58:16 +0100 Subject: [PATCH 02/16] Full pending block mining notifications --- cmd/geth/main.go | 1 + cmd/geth/usage.go | 1 + cmd/utils/flags.go | 7 ++++++- consensus/ethash/ethash.go | 10 +++++----- consensus/ethash/sealer.go | 17 +++++++++++++++-- eth/backend.go | 8 ++++---- les/client.go | 2 +- miner/miner.go | 17 +++++++++-------- 8 files changed, 42 insertions(+), 21 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 86dc6f40fe9c..affcd2eb0529 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -163,6 +163,7 @@ var ( utils.GpoMaxGasPriceFlag, utils.EWASMInterpreterFlag, utils.EVMInterpreterFlag, + utils.MinerNotifyFullFlag, configFileFlag, } diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index ba311bf7f647..35ba5e2d15be 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -179,6 +179,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.MiningEnabledFlag, utils.MinerThreadsFlag, utils.MinerNotifyFlag, + utils.MinerNotifyFullFlag, utils.MinerGasPriceFlag, utils.MinerGasTargetFlag, utils.MinerGasLimitFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 8f9f68ba680e..fbdc6dbd0e20 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -413,6 +413,10 @@ var ( Name: "miner.notify", Usage: "Comma separated HTTP URL list to notify of new work packages", } + MinerNotifyFullFlag = cli.BoolFlag{ + Name: "miner.notify.full", + Usage: "Notify with pending block bodies instead of work packages", + } MinerGasTargetFlag = cli.Uint64Flag{ Name: "miner.gastarget", Usage: "Target gas floor for mined blocks", @@ -1385,6 +1389,7 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) { if ctx.GlobalIsSet(MinerNotifyFlag.Name) { cfg.Notify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",") } + cfg.NotifyFull = ctx.GlobalBool(MinerNotifyFullFlag.Name) if ctx.GlobalIsSet(LegacyMinerExtraDataFlag.Name) { cfg.ExtraData = []byte(ctx.GlobalString(LegacyMinerExtraDataFlag.Name)) log.Warn("The flag --extradata is deprecated and will be removed in the future, please use --miner.extradata") @@ -1855,7 +1860,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readOnly bool) (chain *core.B DatasetsInMem: eth.DefaultConfig.Ethash.DatasetsInMem, DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk, DatasetsLockMmap: eth.DefaultConfig.Ethash.DatasetsLockMmap, - }, nil, false) + }, nil, false, false) } } if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 550d99893d89..671c183994a0 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -48,7 +48,7 @@ var ( two256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) // sharedEthash is a full instance that can be shared between multiple users. - sharedEthash = New(Config{"", 3, 0, false, "", 1, 0, false, ModeNormal, nil}, nil, false) + sharedEthash = New(Config{"", 3, 0, false, "", 1, 0, false, ModeNormal, nil}, nil, false, false) // algorithmRevision is the data structure version used for file naming. algorithmRevision = 23 @@ -441,7 +441,7 @@ type Ethash struct { // New creates a full sized ethash PoW scheme and starts a background thread for // remote mining, also optionally notifying a batch of remote services of new work // packages. -func New(config Config, notify []string, noverify bool) *Ethash { +func New(config Config, notify []string, notifyFull bool, noverify bool) *Ethash { if config.Log == nil { config.Log = log.Root() } @@ -462,13 +462,13 @@ func New(config Config, notify []string, noverify bool) *Ethash { update: make(chan struct{}), hashrate: metrics.NewMeterForced(), } - ethash.remote = startRemoteSealer(ethash, notify, noverify) + ethash.remote = startRemoteSealer(ethash, notify, notifyFull, noverify) return ethash } // NewTester creates a small sized ethash PoW scheme useful only for testing // purposes. -func NewTester(notify []string, noverify bool) *Ethash { +func NewTester(notify []string, notifyFull bool, noverify bool) *Ethash { ethash := &Ethash{ config: Config{PowMode: ModeTest, Log: log.Root()}, caches: newlru("cache", 1, newCache), @@ -476,7 +476,7 @@ func NewTester(notify []string, noverify bool) *Ethash { update: make(chan struct{}), hashrate: metrics.NewMeterForced(), } - ethash.remote = startRemoteSealer(ethash, notify, noverify) + ethash.remote = startRemoteSealer(ethash, notify, notifyFull, noverify) return ethash } diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go index 205353402852..daa0c67aef9c 100644 --- a/consensus/ethash/sealer.go +++ b/consensus/ethash/sealer.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/internal/serialization" ) const ( @@ -201,6 +202,7 @@ type remoteSealer struct { ethash *Ethash noverify bool notifyURLs []string + notifyFull bool results chan<- *types.Block workCh chan *sealTask // Notification channel to push new work and relative result channel to remote sealer fetchWorkCh chan *sealWork // Channel used for remote sealer to fetch mining work @@ -241,12 +243,13 @@ type sealWork struct { res chan [4]string } -func startRemoteSealer(ethash *Ethash, urls []string, noverify bool) *remoteSealer { +func startRemoteSealer(ethash *Ethash, urls []string, notifyFull bool, noverify bool) *remoteSealer { ctx, cancel := context.WithCancel(context.Background()) s := &remoteSealer{ ethash: ethash, noverify: noverify, notifyURLs: urls, + notifyFull: notifyFull, notifyCtx: ctx, cancelNotify: cancel, works: make(map[common.Hash]*types.Block), @@ -358,7 +361,17 @@ func (s *remoteSealer) makeWork(block *types.Block) { // new work to be processed. func (s *remoteSealer) notifyWork() { work := s.currentWork - blob, _ := json.Marshal(work) + var blob []byte + if s.notifyFull { + blockSerialized, err := serialization.RPCMarshalBlock(s.currentBlock, false, false) + if err != nil { + s.ethash.config.Log.Error("Unable to marshal current block for the notification", "err", err) + return + } + blob, _ = json.Marshal(blockSerialized) + } else { + blob, _ = json.Marshal(s.currentWork) + } s.reqWG.Add(len(s.notifyURLs)) for _, url := range s.notifyURLs { go s.sendNotification(s.notifyCtx, url, blob, work) diff --git a/eth/backend.go b/eth/backend.go index a6390facb30b..bc75edd6afcc 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -132,7 +132,7 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) { chainDb: chainDb, eventMux: stack.EventMux(), accountManager: stack.AccountManager(), - engine: CreateConsensusEngine(stack, chainConfig, &config.Ethash, config.Miner.Notify, config.Miner.Noverify, chainDb), + engine: CreateConsensusEngine(stack, chainConfig, &config.Ethash, config.Miner.Notify, config.Miner.NotifyFull, config.Miner.Noverify, chainDb), closeBloomHandler: make(chan struct{}), networkID: config.NetworkId, gasPrice: config.Miner.GasPrice, @@ -270,7 +270,7 @@ func makeExtraData(extra []byte) []byte { } // CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service -func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine { +func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, notifyFull bool, noverify bool, db ethdb.Database) consensus.Engine { // If proof-of-authority is requested, set it up if chainConfig.Clique != nil { return clique.New(chainConfig.Clique, db) @@ -282,7 +282,7 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, co return ethash.NewFaker() case ethash.ModeTest: log.Warn("Ethash used in test mode") - return ethash.NewTester(nil, noverify) + return ethash.NewTester(nil, notifyFull, noverify) case ethash.ModeShared: log.Warn("Ethash used in shared mode") return ethash.NewShared() @@ -296,7 +296,7 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, co DatasetsInMem: config.DatasetsInMem, DatasetsOnDisk: config.DatasetsOnDisk, DatasetsLockMmap: config.DatasetsLockMmap, - }, notify, noverify) + }, notify, notifyFull, noverify) engine.SetThreads(-1) // Disable CPU mining return engine } diff --git a/les/client.go b/les/client.go index d8cb6e385ac8..5871cc006aec 100644 --- a/les/client.go +++ b/les/client.go @@ -105,7 +105,7 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) { eventMux: stack.EventMux(), reqDist: newRequestDistributor(peers, &mclock.System{}), accountManager: stack.AccountManager(), - engine: eth.CreateConsensusEngine(stack, chainConfig, &config.Ethash, nil, false, chainDb), + engine: eth.CreateConsensusEngine(stack, chainConfig, &config.Ethash, nil, false, false, chainDb), bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), valueTracker: lpc.NewValueTracker(lespayDb, &mclock.System{}, requestList, time.Minute, 1/float64(time.Hour), 1/float64(time.Hour*100), 1/float64(time.Hour*1000)), diff --git a/miner/miner.go b/miner/miner.go index 20169f5007e2..e7cb1e330a0c 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -42,14 +42,15 @@ type Backend interface { // Config is the configuration parameters of mining. type Config struct { - Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards (default = first account) - Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages(only useful in ethash). - ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner - GasFloor uint64 // Target gas floor for mined blocks. - GasCeil uint64 // Target gas ceiling for mined blocks. - GasPrice *big.Int // Minimum gas price for mining a transaction - Recommit time.Duration // The time interval for miner to re-create mining work. - Noverify bool // Disable remote mining solution verification(only useful in ethash). + Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards (default = first account) + Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages(only useful in ethash). + NotifyFull bool `toml:",omitempty"` + ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner + GasFloor uint64 // Target gas floor for mined blocks. + GasCeil uint64 // Target gas ceiling for mined blocks. + GasPrice *big.Int // Minimum gas price for mining a transaction + Recommit time.Duration // The time interval for miner to re-create mining work. + Noverify bool // Disable remote mining solution verification(only useful in ethash). } // Miner creates blocks and searches for proof-of-work values. From a5788fa21e56b302b80ecca151b684dbbb836ed7 Mon Sep 17 00:00:00 2001 From: AlexSSD7 Date: Fri, 12 Feb 2021 21:58:23 +0100 Subject: [PATCH 03/16] Fix tests --- consensus/ethash/algorithm_test.go | 2 +- consensus/ethash/ethash_test.go | 10 +++++----- consensus/ethash/sealer_test.go | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/consensus/ethash/algorithm_test.go b/consensus/ethash/algorithm_test.go index 51fb6b124de9..add823dd5533 100644 --- a/consensus/ethash/algorithm_test.go +++ b/consensus/ethash/algorithm_test.go @@ -729,7 +729,7 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) { go func(idx int) { defer pend.Done() - ethash := New(Config{cachedir, 0, 1, false, "", 0, 0, false, ModeNormal, nil}, nil, false) + ethash := New(Config{cachedir, 0, 1, false, "", 0, 0, false, ModeNormal, nil}, nil, false, false) defer ethash.Close() if err := ethash.VerifySeal(nil, block.Header()); err != nil { t.Errorf("proc %d: block verification failed: %v", idx, err) diff --git a/consensus/ethash/ethash_test.go b/consensus/ethash/ethash_test.go index adbf1ccfebbd..e8bbcd8ea14e 100644 --- a/consensus/ethash/ethash_test.go +++ b/consensus/ethash/ethash_test.go @@ -34,7 +34,7 @@ import ( func TestTestMode(t *testing.T) { header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} - ethash := NewTester(nil, false) + ethash := NewTester(nil, false, false) defer ethash.Close() results := make(chan *types.Block) @@ -62,7 +62,7 @@ func TestCacheFileEvict(t *testing.T) { t.Fatal(err) } defer os.RemoveAll(tmpdir) - e := New(Config{CachesInMem: 3, CachesOnDisk: 10, CacheDir: tmpdir, PowMode: ModeTest}, nil, false) + e := New(Config{CachesInMem: 3, CachesOnDisk: 10, CacheDir: tmpdir, PowMode: ModeTest}, nil, false, false) defer e.Close() workers := 8 @@ -91,7 +91,7 @@ func verifyTest(wg *sync.WaitGroup, e *Ethash, workerIndex, epochs int) { } func TestRemoteSealer(t *testing.T) { - ethash := NewTester(nil, false) + ethash := NewTester(nil, false, false) defer ethash.Close() api := &API{ethash} @@ -134,7 +134,7 @@ func TestHashRate(t *testing.T) { expect uint64 ids = []common.Hash{common.HexToHash("a"), common.HexToHash("b"), common.HexToHash("c")} ) - ethash := NewTester(nil, false) + ethash := NewTester(nil, false, false) defer ethash.Close() if tot := ethash.Hashrate(); tot != 0 { @@ -154,7 +154,7 @@ func TestHashRate(t *testing.T) { } func TestClosedRemoteSealer(t *testing.T) { - ethash := NewTester(nil, false) + ethash := NewTester(nil, false, false) time.Sleep(1 * time.Second) // ensure exit channel is listening ethash.Close() diff --git a/consensus/ethash/sealer_test.go b/consensus/ethash/sealer_test.go index 20ed2a41844f..a733ef115bfd 100644 --- a/consensus/ethash/sealer_test.go +++ b/consensus/ethash/sealer_test.go @@ -49,7 +49,7 @@ func TestRemoteNotify(t *testing.T) { defer server.Close() // Create the custom ethash engine. - ethash := NewTester([]string{server.URL}, false) + ethash := NewTester([]string{server.URL}, false, false) defer ethash.Close() // Stream a work task and ensure the notification bubbles out. @@ -93,7 +93,7 @@ func TestRemoteMultiNotify(t *testing.T) { defer server.Close() // Create the custom ethash engine. - ethash := NewTester([]string{server.URL}, false) + ethash := NewTester([]string{server.URL}, false, false) ethash.config.Log = testlog.Logger(t, log.LvlWarn) defer ethash.Close() @@ -121,7 +121,7 @@ func TestRemoteMultiNotify(t *testing.T) { // Tests whether stale solutions are correctly processed. func TestStaleSubmission(t *testing.T) { - ethash := NewTester(nil, true) + ethash := NewTester(nil, false, true) defer ethash.Close() api := &API{ethash} From 46d5fc66f96dc543aed22aa14807333ce15a5c49 Mon Sep 17 00:00:00 2001 From: AlexSSD7 Date: Fri, 12 Feb 2021 22:14:26 +0100 Subject: [PATCH 04/16] Fix CreateConsensusEngine --- eth/ethconfig/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index e192e4d333e8..bb07e77412aa 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -200,7 +200,7 @@ type Config struct { } // CreateConsensusEngine creates a consensus engine for the given chain configuration. -func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine { +func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, notifyFull bool, noverify bool, db ethdb.Database) consensus.Engine { // If proof-of-authority is requested, set it up if chainConfig.Clique != nil { return clique.New(chainConfig.Clique, db) @@ -212,7 +212,7 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, co return ethash.NewFaker() case ethash.ModeTest: log.Warn("Ethash used in test mode") - return ethash.NewTester(nil, noverify) + return ethash.NewTester(nil, notifyFull, noverify) case ethash.ModeShared: log.Warn("Ethash used in shared mode") return ethash.NewShared() @@ -226,7 +226,7 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, co DatasetsInMem: config.DatasetsInMem, DatasetsOnDisk: config.DatasetsOnDisk, DatasetsLockMmap: config.DatasetsLockMmap, - }, notify, noverify) + }, notify, notifyFull, noverify) engine.SetThreads(-1) // Disable CPU mining return engine } From f120b8683333ce717b532a19d2047d0b12ff568b Mon Sep 17 00:00:00 2001 From: AlexSSD7 Date: Fri, 12 Feb 2021 22:51:37 +0100 Subject: [PATCH 05/16] Test coverage for pending block notifications --- consensus/ethash/sealer_test.go | 85 +++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/consensus/ethash/sealer_test.go b/consensus/ethash/sealer_test.go index a733ef115bfd..d482210d36e8 100644 --- a/consensus/ethash/sealer_test.go +++ b/consensus/ethash/sealer_test.go @@ -22,6 +22,7 @@ import ( "math/big" "net/http" "net/http/httptest" + "strconv" "testing" "time" @@ -74,6 +75,45 @@ func TestRemoteNotify(t *testing.T) { } } +// Tests whether remote HTTP servers are correctly notified of new work. (Full pending block body / --miner.notify.full) +func TestRemoteNotifyFull(t *testing.T) { + // Start a simple web server to capture notifications. + sink := make(chan map[string]interface{}) + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + blob, err := ioutil.ReadAll(req.Body) + if err != nil { + t.Errorf("failed to read miner notification: %v", err) + } + var work map[string]interface{} + if err := json.Unmarshal(blob, &work); err != nil { + t.Errorf("failed to unmarshal miner notification: %v", err) + } + sink <- work + })) + defer server.Close() + + // Create the custom ethash engine. + ethash := NewTester([]string{server.URL}, true, false) + defer ethash.Close() + + // Stream a work task and ensure the notification bubbles out. + header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} + block := types.NewBlockWithHeader(header) + + ethash.Seal(nil, block, nil, nil) + select { + case work := <-sink: + if want := "0x" + strconv.FormatUint(header.Number.Uint64(), 16); work["number"] != want { + t.Errorf("pending block number mismatch: have %v, want %v", work["number"], want) + } + if want := "0x" + header.Difficulty.Text(16); work["difficulty"] != want { + t.Errorf("pending block difficulty mismatch: have %s, want %s", work["difficulty"], want) + } + case <-time.After(3 * time.Second): + t.Fatalf("notification timed out") + } +} + // Tests that pushing work packages fast to the miner doesn't cause any data race // issues in the notifications. func TestRemoteMultiNotify(t *testing.T) { @@ -119,6 +159,51 @@ func TestRemoteMultiNotify(t *testing.T) { } } +// Tests that pushing work packages fast to the miner doesn't cause any data race +// issues in the notifications. Full pending block body / --miner.notify.full) +func TestRemoteMultiNotifyFull(t *testing.T) { + // Start a simple web server to capture notifications. + sink := make(chan map[string]interface{}, 64) + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + blob, err := ioutil.ReadAll(req.Body) + if err != nil { + t.Errorf("failed to read miner notification: %v", err) + } + var work map[string]interface{} + if err := json.Unmarshal(blob, &work); err != nil { + t.Errorf("failed to unmarshal miner notification: %v", err) + } + sink <- work + })) + defer server.Close() + + // Create the custom ethash engine. + ethash := NewTester([]string{server.URL}, true, false) + ethash.config.Log = testlog.Logger(t, log.LvlWarn) + defer ethash.Close() + + // Provide a results reader. + // Otherwise the unread results will be logged asynchronously + // and this can happen after the test is finished, causing a panic. + results := make(chan *types.Block, cap(sink)) + + // Stream a lot of work task and ensure all the notifications bubble out. + for i := 0; i < cap(sink); i++ { + header := &types.Header{Number: big.NewInt(int64(i)), Difficulty: big.NewInt(100)} + block := types.NewBlockWithHeader(header) + ethash.Seal(nil, block, results, nil) + } + + for i := 0; i < cap(sink); i++ { + select { + case <-sink: + <-results + case <-time.After(10 * time.Second): + t.Fatalf("notification %d timed out", i) + } + } +} + // Tests whether stale solutions are correctly processed. func TestStaleSubmission(t *testing.T) { ethash := NewTester(nil, false, true) From 22bb4d1773bf044032d769327e4fb21812308bf1 Mon Sep 17 00:00:00 2001 From: AlexSSD7 Date: Thu, 25 Feb 2021 22:21:36 +0100 Subject: [PATCH 06/16] Remove unused newRPCRawTransactionFromBlockIndex duplicate --- internal/serialization/serialization.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/internal/serialization/serialization.go b/internal/serialization/serialization.go index 346909575c14..26d1cdb962fb 100644 --- a/internal/serialization/serialization.go +++ b/internal/serialization/serialization.go @@ -113,16 +113,6 @@ func NewRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransacti return NewRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index) } -// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. -func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes { - txs := b.Transactions() - if index >= uint64(len(txs)) { - return nil - } - blob, _ := txs[index].MarshalBinary() - return blob -} - // NewRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. func NewRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction { for idx, tx := range b.Transactions() { From 32dd29390d04c4d78bf5ee5247e5db21a987a84f Mon Sep 17 00:00:00 2001 From: AlexSSD7 Date: Fri, 26 Feb 2021 10:37:14 +0100 Subject: [PATCH 07/16] Update the flag description --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index dc03ac3a567b..b499a8f5d9c5 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -425,7 +425,7 @@ var ( } MinerNotifyFullFlag = cli.BoolFlag{ Name: "miner.notify.full", - Usage: "Notify with pending block bodies instead of work packages", + Usage: "Notify with pending block headers instead of work packages", } MinerGasTargetFlag = cli.Uint64Flag{ Name: "miner.gastarget", From f9e504636fffc05f944683758f5e2838901452c5 Mon Sep 17 00:00:00 2001 From: AlexSSD7 Date: Fri, 26 Feb 2021 10:37:55 +0100 Subject: [PATCH 08/16] Add miner notify full comment to the Config struct --- miner/miner.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miner/miner.go b/miner/miner.go index e7cb1e330a0c..31773e256480 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -43,8 +43,8 @@ type Backend interface { // Config is the configuration parameters of mining. type Config struct { Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards (default = first account) - Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages(only useful in ethash). - NotifyFull bool `toml:",omitempty"` + Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages (only useful in ethash). + NotifyFull bool `toml:",omitempty"` // Notify with pending block bodies instead of work packages ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner GasFloor uint64 // Target gas floor for mined blocks. GasCeil uint64 // Target gas ceiling for mined blocks. From 733012726e90321356d5e0a232da25c6146c07f1 Mon Sep 17 00:00:00 2001 From: AlexSSD7 Date: Mon, 1 Mar 2021 13:58:32 +0100 Subject: [PATCH 09/16] Use types.Header instead of MarshalRPCBlock --- consensus/ethash/sealer.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go index daa0c67aef9c..b89bca97285b 100644 --- a/consensus/ethash/sealer.go +++ b/consensus/ethash/sealer.go @@ -34,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/internal/serialization" ) const ( @@ -362,13 +361,13 @@ func (s *remoteSealer) makeWork(block *types.Block) { func (s *remoteSealer) notifyWork() { work := s.currentWork var blob []byte + var err error if s.notifyFull { - blockSerialized, err := serialization.RPCMarshalBlock(s.currentBlock, false, false) + blob, err = json.Marshal(s.currentBlock.Header()) if err != nil { s.ethash.config.Log.Error("Unable to marshal current block for the notification", "err", err) return } - blob, _ = json.Marshal(blockSerialized) } else { blob, _ = json.Marshal(s.currentWork) } From a44ad82ad92ddeea53416f47ea4c9f389a5f1a66 Mon Sep 17 00:00:00 2001 From: AlexSSD7 Date: Mon, 1 Mar 2021 14:06:16 +0100 Subject: [PATCH 10/16] Remove serialization package --- eth/api.go | 4 +- internal/ethapi/api.go | 202 +++++++++++++++++++++--- internal/serialization/serialization.go | 183 --------------------- 3 files changed, 181 insertions(+), 208 deletions(-) delete mode 100644 internal/serialization/serialization.go diff --git a/eth/api.go b/eth/api.go index fbfa1e42acba..53ef91392ba6 100644 --- a/eth/api.go +++ b/eth/api.go @@ -34,7 +34,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/internal/serialization" + "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" @@ -346,7 +346,7 @@ func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, } else { blockRlp = fmt.Sprintf("0x%x", rlpBytes) } - if blockJSON, err = serialization.RPCMarshalBlock(block, true, true); err != nil { + if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true); err != nil { blockJSON = map[string]interface{}{"error": err.Error()} } results = append(results, &BadBlockArgs{ diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 26f1023cc248..622063cf6497 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -39,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/internal/serialization" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" @@ -100,26 +99,26 @@ func NewPublicTxPoolAPI(b Backend) *PublicTxPoolAPI { } // Content returns the transactions contained within the transaction pool. -func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*serialization.RPCTransaction { - content := map[string]map[string]map[string]*serialization.RPCTransaction{ - "pending": make(map[string]map[string]*serialization.RPCTransaction), - "queued": make(map[string]map[string]*serialization.RPCTransaction), +func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { + content := map[string]map[string]map[string]*RPCTransaction{ + "pending": make(map[string]map[string]*RPCTransaction), + "queued": make(map[string]map[string]*RPCTransaction), } pending, queue := s.b.TxPoolContent() // Flatten the pending transactions for account, txs := range pending { - dump := make(map[string]*serialization.RPCTransaction) + dump := make(map[string]*RPCTransaction) for _, tx := range txs { - dump[fmt.Sprintf("%d", tx.Nonce())] = serialization.NewRPCPendingTransaction(tx) + dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx) } content["pending"][account.Hex()] = dump } // Flatten the queued transactions for account, txs := range queue { - dump := make(map[string]*serialization.RPCTransaction) + dump := make(map[string]*RPCTransaction) for _, tx := range txs { - dump[fmt.Sprintf("%d", tx.Nonce())] = serialization.NewRPCPendingTransaction(tx) + dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx) } content["queued"][account.Hex()] = dump } @@ -1122,10 +1121,69 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes { return formatted } +// RPCMarshalHeader converts the given header to the RPC output . +func RPCMarshalHeader(head *types.Header) map[string]interface{} { + return map[string]interface{}{ + "number": (*hexutil.Big)(head.Number), + "hash": head.Hash(), + "parentHash": head.ParentHash, + "nonce": head.Nonce, + "mixHash": head.MixDigest, + "sha3Uncles": head.UncleHash, + "logsBloom": head.Bloom, + "stateRoot": head.Root, + "miner": head.Coinbase, + "difficulty": (*hexutil.Big)(head.Difficulty), + "extraData": hexutil.Bytes(head.Extra), + "size": hexutil.Uint64(head.Size()), + "gasLimit": hexutil.Uint64(head.GasLimit), + "gasUsed": hexutil.Uint64(head.GasUsed), + "timestamp": hexutil.Uint64(head.Time), + "transactionsRoot": head.TxHash, + "receiptsRoot": head.ReceiptHash, + } +} + +// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are +// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain +// transaction hashes. +func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { + fields := RPCMarshalHeader(block.Header()) + fields["size"] = hexutil.Uint64(block.Size()) + + if inclTx { + formatTx := func(tx *types.Transaction) (interface{}, error) { + return tx.Hash(), nil + } + if fullTx { + formatTx = func(tx *types.Transaction) (interface{}, error) { + return newRPCTransactionFromBlockHash(block, tx.Hash()), nil + } + } + txs := block.Transactions() + transactions := make([]interface{}, len(txs)) + var err error + for i, tx := range txs { + if transactions[i], err = formatTx(tx); err != nil { + return nil, err + } + } + fields["transactions"] = transactions + } + uncles := block.Uncles() + uncleHashes := make([]common.Hash, len(uncles)) + for i, uncle := range uncles { + uncleHashes[i] = uncle.Hash() + } + fields["uncles"] = uncleHashes + + return fields, nil +} + // rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires // a `PublicBlockchainAPI`. func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} { - fields := serialization.RPCMarshalHeader(header) + fields := RPCMarshalHeader(header) fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, header.Hash())) return fields } @@ -1133,7 +1191,7 @@ func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *type // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires // a `PublicBlockchainAPI`. func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields, err := serialization.RPCMarshalBlock(b, inclTx, fullTx) + fields, err := RPCMarshalBlock(b, inclTx, fullTx) if err != nil { return nil, err } @@ -1143,6 +1201,104 @@ func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Bloc return fields, err } +// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction +type RPCTransaction struct { + BlockHash *common.Hash `json:"blockHash"` + BlockNumber *hexutil.Big `json:"blockNumber"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + Hash common.Hash `json:"hash"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + Type hexutil.Uint64 `json:"type"` + Accesses *types.AccessList `json:"accessList,omitempty"` + ChainID *hexutil.Big `json:"chainId,omitempty"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` +} + +// newRPCTransaction returns a transaction that will serialize to the RPC +// representation, with the given location metadata set (if available). +func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction { + // Determine the signer. For replay-protected transactions, use the most permissive + // signer, because we assume that signers are backwards-compatible with old + // transactions. For non-protected transactions, the homestead signer signer is used + // because the return value of ChainId is zero for those transactions. + var signer types.Signer + if tx.Protected() { + signer = types.LatestSignerForChainID(tx.ChainId()) + } else { + signer = types.HomesteadSigner{} + } + + from, _ := types.Sender(signer, tx) + v, r, s := tx.RawSignatureValues() + result := &RPCTransaction{ + Type: hexutil.Uint64(tx.Type()), + From: from, + Gas: hexutil.Uint64(tx.Gas()), + GasPrice: (*hexutil.Big)(tx.GasPrice()), + Hash: tx.Hash(), + Input: hexutil.Bytes(tx.Data()), + Nonce: hexutil.Uint64(tx.Nonce()), + To: tx.To(), + Value: (*hexutil.Big)(tx.Value()), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), + } + if blockHash != (common.Hash{}) { + result.BlockHash = &blockHash + result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) + result.TransactionIndex = (*hexutil.Uint64)(&index) + } + if tx.Type() == types.AccessListTxType { + al := tx.AccessList() + result.Accesses = &al + result.ChainID = (*hexutil.Big)(tx.ChainId()) + } + return result +} + +// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation +func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction { + return newRPCTransaction(tx, common.Hash{}, 0, 0) +} + +// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. +func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction { + txs := b.Transactions() + if index >= uint64(len(txs)) { + return nil + } + return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index) +} + +// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. +func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes { + txs := b.Transactions() + if index >= uint64(len(txs)) { + return nil + } + blob, _ := txs[index].MarshalBinary() + return blob +} + +// newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. +func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction { + for idx, tx := range b.Transactions() { + if tx.Hash() == hash { + return newRPCTransactionFromBlockIndex(b, uint64(idx)) + } + } + return nil +} + // PublicTransactionPoolAPI exposes methods for the RPC interface type PublicTransactionPoolAPI struct { b Backend @@ -1177,17 +1333,17 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Co } // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. -func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *serialization.RPCTransaction { +func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return serialization.NewRPCTransactionFromBlockIndex(block, uint64(index)) + return newRPCTransactionFromBlockIndex(block, uint64(index)) } return nil } // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. -func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *serialization.RPCTransaction { +func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { - return serialization.NewRPCTransactionFromBlockIndex(block, uint64(index)) + return newRPCTransactionFromBlockIndex(block, uint64(index)) } return nil } @@ -1195,7 +1351,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return serialization.NewRPCRawTransactionFromBlockIndex(block, uint64(index)) + return newRPCRawTransactionFromBlockIndex(block, uint64(index)) } return nil } @@ -1203,7 +1359,7 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx co // GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { - return serialization.NewRPCRawTransactionFromBlockIndex(block, uint64(index)) + return newRPCRawTransactionFromBlockIndex(block, uint64(index)) } return nil } @@ -1228,18 +1384,18 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr } // GetTransactionByHash returns the transaction for the given hash -func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*serialization.RPCTransaction, error) { +func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { // Try to return an already finalized transaction tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) if err != nil { return nil, err } if tx != nil { - return serialization.NewRPCTransaction(tx, blockHash, blockNumber, index), nil + return newRPCTransaction(tx, blockHash, blockNumber, index), nil } // No finalized transaction, try to retrieve it from the pool if tx := s.b.GetPoolTransaction(hash); tx != nil { - return serialization.NewRPCPendingTransaction(tx), nil + return newRPCPendingTransaction(tx), nil } // Transaction unknown, return as such @@ -1598,7 +1754,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen // PendingTransactions returns the transactions that are in the transaction pool // and have a from address that is one of the accounts this node manages. -func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*serialization.RPCTransaction, error) { +func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) { pending, err := s.b.GetPoolTransactions() if err != nil { return nil, err @@ -1609,11 +1765,11 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*serialization.RPCTr accounts[account.Address] = struct{}{} } } - transactions := make([]*serialization.RPCTransaction, 0, len(pending)) + transactions := make([]*RPCTransaction, 0, len(pending)) for _, tx := range pending { from, _ := types.Sender(s.signer, tx) if _, exists := accounts[from]; exists { - transactions = append(transactions, serialization.NewRPCPendingTransaction(tx)) + transactions = append(transactions, newRPCPendingTransaction(tx)) } } return transactions, nil diff --git a/internal/serialization/serialization.go b/internal/serialization/serialization.go deleted file mode 100644 index 26d1cdb962fb..000000000000 --- a/internal/serialization/serialization.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2021 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package serialization - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/rlp" -) - -// NewRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. -func NewRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes { - txs := b.Transactions() - if index >= uint64(len(txs)) { - return nil - } - blob, _ := rlp.EncodeToBytes(txs[index]) - return blob -} - -// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction -type RPCTransaction struct { - BlockHash *common.Hash `json:"blockHash"` - BlockNumber *hexutil.Big `json:"blockNumber"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - Hash common.Hash `json:"hash"` - Input hexutil.Bytes `json:"input"` - Nonce hexutil.Uint64 `json:"nonce"` - To *common.Address `json:"to"` - TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` - Value *hexutil.Big `json:"value"` - Type hexutil.Uint64 `json:"type"` - Accesses *types.AccessList `json:"accessList,omitempty"` - ChainID *hexutil.Big `json:"chainId,omitempty"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` -} - -// NewRPCTransaction returns a transaction that will serialize to the RPC -// representation, with the given location metadata set (if available). -func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction { - // Determine the signer. For replay-protected transactions, use the most permissive - // signer, because we assume that signers are backwards-compatible with old - // transactions. For non-protected transactions, the homestead signer signer is used - // because the return value of ChainId is zero for those transactions. - var signer types.Signer - if tx.Protected() { - signer = types.LatestSignerForChainID(tx.ChainId()) - } else { - signer = types.HomesteadSigner{} - } - - from, _ := types.Sender(signer, tx) - v, r, s := tx.RawSignatureValues() - result := &RPCTransaction{ - Type: hexutil.Uint64(tx.Type()), - From: from, - Gas: hexutil.Uint64(tx.Gas()), - GasPrice: (*hexutil.Big)(tx.GasPrice()), - Hash: tx.Hash(), - Input: hexutil.Bytes(tx.Data()), - Nonce: hexutil.Uint64(tx.Nonce()), - To: tx.To(), - Value: (*hexutil.Big)(tx.Value()), - V: (*hexutil.Big)(v), - R: (*hexutil.Big)(r), - S: (*hexutil.Big)(s), - } - if blockHash != (common.Hash{}) { - result.BlockHash = &blockHash - result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) - result.TransactionIndex = (*hexutil.Uint64)(&index) - } - if tx.Type() == types.AccessListTxType { - al := tx.AccessList() - result.Accesses = &al - result.ChainID = (*hexutil.Big)(tx.ChainId()) - } - return result -} - -// NewRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation -func NewRPCPendingTransaction(tx *types.Transaction) *RPCTransaction { - return NewRPCTransaction(tx, common.Hash{}, 0, 0) -} - -// NewRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. -func NewRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction { - txs := b.Transactions() - if index >= uint64(len(txs)) { - return nil - } - return NewRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index) -} - -// NewRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. -func NewRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction { - for idx, tx := range b.Transactions() { - if tx.Hash() == hash { - return NewRPCTransactionFromBlockIndex(b, uint64(idx)) - } - } - return nil -} - -// RPCMarshalHeader converts the given header to the RPC output . -func RPCMarshalHeader(head *types.Header) map[string]interface{} { - return map[string]interface{}{ - "number": (*hexutil.Big)(head.Number), - "hash": head.Hash(), - "parentHash": head.ParentHash, - "nonce": head.Nonce, - "mixHash": head.MixDigest, - "sha3Uncles": head.UncleHash, - "logsBloom": head.Bloom, - "stateRoot": head.Root, - "miner": head.Coinbase, - "difficulty": (*hexutil.Big)(head.Difficulty), - "extraData": hexutil.Bytes(head.Extra), - "size": hexutil.Uint64(head.Size()), - "gasLimit": hexutil.Uint64(head.GasLimit), - "gasUsed": hexutil.Uint64(head.GasUsed), - "timestamp": hexutil.Uint64(head.Time), - "transactionsRoot": head.TxHash, - "receiptsRoot": head.ReceiptHash, - } -} - -// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are -// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain -// transaction hashes. -func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields := RPCMarshalHeader(block.Header()) - fields["size"] = hexutil.Uint64(block.Size()) - - if inclTx { - formatTx := func(tx *types.Transaction) (interface{}, error) { - return tx.Hash(), nil - } - if fullTx { - formatTx = func(tx *types.Transaction) (interface{}, error) { - return NewRPCTransactionFromBlockHash(block, tx.Hash()), nil - } - } - txs := block.Transactions() - transactions := make([]interface{}, len(txs)) - var err error - for i, tx := range txs { - if transactions[i], err = formatTx(tx); err != nil { - return nil, err - } - } - fields["transactions"] = transactions - } - uncles := block.Uncles() - uncleHashes := make([]common.Hash, len(uncles)) - for i, uncle := range uncles { - uncleHashes[i] = uncle.Hash() - } - fields["uncles"] = uncleHashes - - return fields, nil -} From 456bcab1c6c5940445e45563431f29f265701bbf Mon Sep 17 00:00:00 2001 From: AlexSSD7 Date: Mon, 1 Mar 2021 14:52:41 +0100 Subject: [PATCH 11/16] Remove CreateConsensusEngine inside eth/backend.go --- eth/backend.go | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index e789f20dd407..6fbcad1a4bd6 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/clique" - "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" @@ -281,39 +280,6 @@ func makeExtraData(extra []byte) []byte { return extra } -// CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service -func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, notifyFull bool, noverify bool, db ethdb.Database) consensus.Engine { - // If proof-of-authority is requested, set it up - if chainConfig.Clique != nil { - return clique.New(chainConfig.Clique, db) - } - // Otherwise assume proof-of-work - switch config.PowMode { - case ethash.ModeFake: - log.Warn("Ethash used in fake mode") - return ethash.NewFaker() - case ethash.ModeTest: - log.Warn("Ethash used in test mode") - return ethash.NewTester(nil, notifyFull, noverify) - case ethash.ModeShared: - log.Warn("Ethash used in shared mode") - return ethash.NewShared() - default: - engine := ethash.New(ethash.Config{ - CacheDir: stack.ResolvePath(config.CacheDir), - CachesInMem: config.CachesInMem, - CachesOnDisk: config.CachesOnDisk, - CachesLockMmap: config.CachesLockMmap, - DatasetDir: config.DatasetDir, - DatasetsInMem: config.DatasetsInMem, - DatasetsOnDisk: config.DatasetsOnDisk, - DatasetsLockMmap: config.DatasetsLockMmap, - }, notify, notifyFull, noverify) - engine.SetThreads(-1) // Disable CPU mining - return engine - } -} - // APIs return the collection of RPC services the ethereum package offers. // NOTE, some of these services probably need to be moved to somewhere else. func (s *Ethereum) APIs() []rpc.API { From bbc8feb5f11acd10a901255e299ce8295b4f78b4 Mon Sep 17 00:00:00 2001 From: Alexander Sadovskyi Date: Tue, 9 Mar 2021 12:59:13 +0100 Subject: [PATCH 12/16] Ignore header marshaling error Co-authored-by: Martin Holst Swende --- consensus/ethash/sealer.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go index b89bca97285b..ae5ad7e479af 100644 --- a/consensus/ethash/sealer.go +++ b/consensus/ethash/sealer.go @@ -363,11 +363,7 @@ func (s *remoteSealer) notifyWork() { var blob []byte var err error if s.notifyFull { - blob, err = json.Marshal(s.currentBlock.Header()) - if err != nil { - s.ethash.config.Log.Error("Unable to marshal current block for the notification", "err", err) - return - } + blob, _ = json.Marshal(s.currentBlock.Header()) } else { blob, _ = json.Marshal(s.currentWork) } From 082118baa07206aee390db8c3b409f19ec62d5d3 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 23 Mar 2021 15:43:34 +0100 Subject: [PATCH 13/16] consensus/ethash: pass NotifyFull via config instead of constructor parameter --- cmd/utils/flags.go | 2 +- consensus/ethash/algorithm_test.go | 8 ++++++-- consensus/ethash/ethash.go | 18 ++++++++++++----- consensus/ethash/ethash_test.go | 17 +++++++++++----- consensus/ethash/sealer.go | 4 ++-- consensus/ethash/sealer_test.go | 21 ++++++++++++++------ eth/backend.go | 6 +++++- eth/ethconfig/config.go | 32 ++++++++++++++---------------- les/client.go | 2 +- 9 files changed, 70 insertions(+), 40 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ad73e6025e46..b78affe760eb 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1840,7 +1840,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readOnly bool) (chain *core.B DatasetsInMem: ethconfig.Defaults.Ethash.DatasetsInMem, DatasetsOnDisk: ethconfig.Defaults.Ethash.DatasetsOnDisk, DatasetsLockMmap: ethconfig.Defaults.Ethash.DatasetsLockMmap, - }, nil, false, false) + }, nil, false) } } if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { diff --git a/consensus/ethash/algorithm_test.go b/consensus/ethash/algorithm_test.go index bd887be7e4f3..9cc9d535d4ac 100644 --- a/consensus/ethash/algorithm_test.go +++ b/consensus/ethash/algorithm_test.go @@ -726,10 +726,14 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) { for i := 0; i < 3; i++ { pend.Add(1) - go func(idx int) { defer pend.Done() - ethash := New(Config{cachedir, 0, 1, false, "", 0, 0, false, ModeNormal, nil}, nil, false, false) + + config := Config{ + CacheDir: cachedir, + CachesOnDisk: 1, + } + ethash := New(config, nil, false) defer ethash.Close() if err := ethash.verifySeal(nil, block.Header(), false); err != nil { t.Errorf("proc %d: block verification failed: %v", idx, err) diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 671c183994a0..740be941afc4 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -48,7 +48,11 @@ var ( two256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) // sharedEthash is a full instance that can be shared between multiple users. - sharedEthash = New(Config{"", 3, 0, false, "", 1, 0, false, ModeNormal, nil}, nil, false, false) + sharedEthash = New(Config{ + CachesInMem: 3, + DatasetsInMem: 1, + PowMode: ModeNormal, + }, nil, false) // algorithmRevision is the data structure version used for file naming. algorithmRevision = 23 @@ -411,6 +415,10 @@ type Config struct { DatasetsLockMmap bool PowMode Mode + // When set, notifications sent by the remote sealer will + // be block header JSON objects instead of work package arrays. + NotifyFull bool + Log log.Logger `toml:"-"` } @@ -441,7 +449,7 @@ type Ethash struct { // New creates a full sized ethash PoW scheme and starts a background thread for // remote mining, also optionally notifying a batch of remote services of new work // packages. -func New(config Config, notify []string, notifyFull bool, noverify bool) *Ethash { +func New(config Config, notify []string, noverify bool) *Ethash { if config.Log == nil { config.Log = log.Root() } @@ -462,13 +470,13 @@ func New(config Config, notify []string, notifyFull bool, noverify bool) *Ethash update: make(chan struct{}), hashrate: metrics.NewMeterForced(), } - ethash.remote = startRemoteSealer(ethash, notify, notifyFull, noverify) + ethash.remote = startRemoteSealer(ethash, notify, config.NotifyFull, noverify) return ethash } // NewTester creates a small sized ethash PoW scheme useful only for testing // purposes. -func NewTester(notify []string, notifyFull bool, noverify bool) *Ethash { +func NewTester(notify []string, noverify bool) *Ethash { ethash := &Ethash{ config: Config{PowMode: ModeTest, Log: log.Root()}, caches: newlru("cache", 1, newCache), @@ -476,7 +484,7 @@ func NewTester(notify []string, notifyFull bool, noverify bool) *Ethash { update: make(chan struct{}), hashrate: metrics.NewMeterForced(), } - ethash.remote = startRemoteSealer(ethash, notify, notifyFull, noverify) + ethash.remote = startRemoteSealer(ethash, notify, false, noverify) return ethash } diff --git a/consensus/ethash/ethash_test.go b/consensus/ethash/ethash_test.go index 996d4c4836c1..eb3850b3b07d 100644 --- a/consensus/ethash/ethash_test.go +++ b/consensus/ethash/ethash_test.go @@ -34,7 +34,7 @@ import ( func TestTestMode(t *testing.T) { header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} - ethash := NewTester(nil, false, false) + ethash := NewTester(nil, false) defer ethash.Close() results := make(chan *types.Block) @@ -62,7 +62,14 @@ func TestCacheFileEvict(t *testing.T) { t.Fatal(err) } defer os.RemoveAll(tmpdir) - e := New(Config{CachesInMem: 3, CachesOnDisk: 10, CacheDir: tmpdir, PowMode: ModeTest}, nil, false, false) + + config := Config{ + CachesInMem: 3, + CachesOnDisk: 10, + CacheDir: tmpdir, + PowMode: ModeTest, + } + e := New(config, nil, false) defer e.Close() workers := 8 @@ -91,7 +98,7 @@ func verifyTest(wg *sync.WaitGroup, e *Ethash, workerIndex, epochs int) { } func TestRemoteSealer(t *testing.T) { - ethash := NewTester(nil, false, false) + ethash := NewTester(nil, false) defer ethash.Close() api := &API{ethash} @@ -134,7 +141,7 @@ func TestHashRate(t *testing.T) { expect uint64 ids = []common.Hash{common.HexToHash("a"), common.HexToHash("b"), common.HexToHash("c")} ) - ethash := NewTester(nil, false, false) + ethash := NewTester(nil, false) defer ethash.Close() if tot := ethash.Hashrate(); tot != 0 { @@ -154,7 +161,7 @@ func TestHashRate(t *testing.T) { } func TestClosedRemoteSealer(t *testing.T) { - ethash := NewTester(nil, false, false) + ethash := NewTester(nil, false) time.Sleep(1 * time.Second) // ensure exit channel is listening ethash.Close() diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go index ae5ad7e479af..834034e59a70 100644 --- a/consensus/ethash/sealer.go +++ b/consensus/ethash/sealer.go @@ -361,12 +361,12 @@ func (s *remoteSealer) makeWork(block *types.Block) { func (s *remoteSealer) notifyWork() { work := s.currentWork var blob []byte - var err error if s.notifyFull { blob, _ = json.Marshal(s.currentBlock.Header()) } else { - blob, _ = json.Marshal(s.currentWork) + blob, _ = json.Marshal(work) } + s.reqWG.Add(len(s.notifyURLs)) for _, url := range s.notifyURLs { go s.sendNotification(s.notifyCtx, url, blob, work) diff --git a/consensus/ethash/sealer_test.go b/consensus/ethash/sealer_test.go index d482210d36e8..c34e76aec243 100644 --- a/consensus/ethash/sealer_test.go +++ b/consensus/ethash/sealer_test.go @@ -50,7 +50,7 @@ func TestRemoteNotify(t *testing.T) { defer server.Close() // Create the custom ethash engine. - ethash := NewTester([]string{server.URL}, false, false) + ethash := NewTester([]string{server.URL}, false) defer ethash.Close() // Stream a work task and ensure the notification bubbles out. @@ -93,7 +93,12 @@ func TestRemoteNotifyFull(t *testing.T) { defer server.Close() // Create the custom ethash engine. - ethash := NewTester([]string{server.URL}, true, false) + config := Config{ + PowMode: ModeTest, + NotifyFull: true, + Log: testlog.Logger(t, log.LvlWarn), + } + ethash := New(config, []string{server.URL}, false) defer ethash.Close() // Stream a work task and ensure the notification bubbles out. @@ -133,7 +138,7 @@ func TestRemoteMultiNotify(t *testing.T) { defer server.Close() // Create the custom ethash engine. - ethash := NewTester([]string{server.URL}, false, false) + ethash := NewTester([]string{server.URL}, false) ethash.config.Log = testlog.Logger(t, log.LvlWarn) defer ethash.Close() @@ -178,8 +183,12 @@ func TestRemoteMultiNotifyFull(t *testing.T) { defer server.Close() // Create the custom ethash engine. - ethash := NewTester([]string{server.URL}, true, false) - ethash.config.Log = testlog.Logger(t, log.LvlWarn) + config := Config{ + PowMode: ModeTest, + NotifyFull: true, + Log: testlog.Logger(t, log.LvlWarn), + } + ethash := New(config, []string{server.URL}, false) defer ethash.Close() // Provide a results reader. @@ -206,7 +215,7 @@ func TestRemoteMultiNotifyFull(t *testing.T) { // Tests whether stale solutions are correctly processed. func TestStaleSubmission(t *testing.T) { - ethash := NewTester(nil, false, true) + ethash := NewTester(nil, true) defer ethash.Close() api := &API{ethash} diff --git a/eth/backend.go b/eth/backend.go index 6fbcad1a4bd6..9a4bbc80a378 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -121,6 +121,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024) + // Transfer mining-related config to the ethash config. + ethashConfig := config.Ethash + ethashConfig.NotifyFull = config.Miner.NotifyFull + // Assemble the Ethereum object chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/") if err != nil { @@ -140,7 +144,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { chainDb: chainDb, eventMux: stack.EventMux(), accountManager: stack.AccountManager(), - engine: ethconfig.CreateConsensusEngine(stack, chainConfig, &config.Ethash, config.Miner.Notify, config.Miner.NotifyFull, config.Miner.Noverify, chainDb), + engine: ethconfig.CreateConsensusEngine(stack, chainConfig, ðashConfig, config.Miner.Notify, config.Miner.Noverify, chainDb), closeBloomHandler: make(chan struct{}), networkID: config.NetworkId, gasPrice: config.Miner.GasPrice, diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 4c0fb1a70092..2fbd0731bbdd 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -204,7 +204,7 @@ type Config struct { } // CreateConsensusEngine creates a consensus engine for the given chain configuration. -func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, notifyFull bool, noverify bool, db ethdb.Database) consensus.Engine { +func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine { // If proof-of-authority is requested, set it up if chainConfig.Clique != nil { return clique.New(chainConfig.Clique, db) @@ -213,25 +213,23 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, co switch config.PowMode { case ethash.ModeFake: log.Warn("Ethash used in fake mode") - return ethash.NewFaker() case ethash.ModeTest: log.Warn("Ethash used in test mode") - return ethash.NewTester(nil, notifyFull, noverify) case ethash.ModeShared: log.Warn("Ethash used in shared mode") - return ethash.NewShared() - default: - engine := ethash.New(ethash.Config{ - CacheDir: stack.ResolvePath(config.CacheDir), - CachesInMem: config.CachesInMem, - CachesOnDisk: config.CachesOnDisk, - CachesLockMmap: config.CachesLockMmap, - DatasetDir: config.DatasetDir, - DatasetsInMem: config.DatasetsInMem, - DatasetsOnDisk: config.DatasetsOnDisk, - DatasetsLockMmap: config.DatasetsLockMmap, - }, notify, notifyFull, noverify) - engine.SetThreads(-1) // Disable CPU mining - return engine } + engine := ethash.New(ethash.Config{ + PowMode: config.PowMode, + CacheDir: stack.ResolvePath(config.CacheDir), + CachesInMem: config.CachesInMem, + CachesOnDisk: config.CachesOnDisk, + CachesLockMmap: config.CachesLockMmap, + DatasetDir: config.DatasetDir, + DatasetsInMem: config.DatasetsInMem, + DatasetsOnDisk: config.DatasetsOnDisk, + DatasetsLockMmap: config.DatasetsLockMmap, + NotifyFull: config.NotifyFull, + }, notify, noverify) + engine.SetThreads(-1) // Disable CPU mining + return engine } diff --git a/les/client.go b/les/client.go index ab86f854ad29..4d07f844f8ec 100644 --- a/les/client.go +++ b/les/client.go @@ -105,7 +105,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { eventMux: stack.EventMux(), reqDist: newRequestDistributor(peers, &mclock.System{}), accountManager: stack.AccountManager(), - engine: ethconfig.CreateConsensusEngine(stack, chainConfig, &config.Ethash, nil, false, false, chainDb), + engine: ethconfig.CreateConsensusEngine(stack, chainConfig, &config.Ethash, nil, false, chainDb), bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), p2pServer: stack.Server(), From 830e0fc72307e7c5256d881a7f3696a30f1986d9 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 23 Mar 2021 15:45:10 +0100 Subject: [PATCH 14/16] miner: fix typo --- miner/miner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/miner.go b/miner/miner.go index 31773e256480..4d71e307a663 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -44,7 +44,7 @@ type Backend interface { type Config struct { Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards (default = first account) Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages (only useful in ethash). - NotifyFull bool `toml:",omitempty"` // Notify with pending block bodies instead of work packages + NotifyFull bool `toml:",omitempty"` // Notify with pending block headers instead of work packages ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner GasFloor uint64 // Target gas floor for mined blocks. GasCeil uint64 // Target gas ceiling for mined blocks. From c89ed7eeae0444fa3981c4dbfb467be52aeaa22b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 23 Mar 2021 15:49:53 +0100 Subject: [PATCH 15/16] consensus/ethash: read NotifyFull from config internally --- consensus/ethash/ethash.go | 4 ++-- consensus/ethash/sealer.go | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 740be941afc4..fffbb67cc4be 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -470,7 +470,7 @@ func New(config Config, notify []string, noverify bool) *Ethash { update: make(chan struct{}), hashrate: metrics.NewMeterForced(), } - ethash.remote = startRemoteSealer(ethash, notify, config.NotifyFull, noverify) + ethash.remote = startRemoteSealer(ethash, notify, noverify) return ethash } @@ -484,7 +484,7 @@ func NewTester(notify []string, noverify bool) *Ethash { update: make(chan struct{}), hashrate: metrics.NewMeterForced(), } - ethash.remote = startRemoteSealer(ethash, notify, false, noverify) + ethash.remote = startRemoteSealer(ethash, notify, noverify) return ethash } diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go index 834034e59a70..1830e672b1ff 100644 --- a/consensus/ethash/sealer.go +++ b/consensus/ethash/sealer.go @@ -201,7 +201,6 @@ type remoteSealer struct { ethash *Ethash noverify bool notifyURLs []string - notifyFull bool results chan<- *types.Block workCh chan *sealTask // Notification channel to push new work and relative result channel to remote sealer fetchWorkCh chan *sealWork // Channel used for remote sealer to fetch mining work @@ -242,13 +241,12 @@ type sealWork struct { res chan [4]string } -func startRemoteSealer(ethash *Ethash, urls []string, notifyFull bool, noverify bool) *remoteSealer { +func startRemoteSealer(ethash *Ethash, urls []string, noverify bool) *remoteSealer { ctx, cancel := context.WithCancel(context.Background()) s := &remoteSealer{ ethash: ethash, noverify: noverify, notifyURLs: urls, - notifyFull: notifyFull, notifyCtx: ctx, cancelNotify: cancel, works: make(map[common.Hash]*types.Block), @@ -360,8 +358,11 @@ func (s *remoteSealer) makeWork(block *types.Block) { // new work to be processed. func (s *remoteSealer) notifyWork() { work := s.currentWork + + // Encode the JSON payload of the notification. When NotifyFull is set, + // this is the complete block header, otherwise it is a JSON array. var blob []byte - if s.notifyFull { + if s.ethash.config.NotifyFull { blob, _ = json.Marshal(s.currentBlock.Header()) } else { blob, _ = json.Marshal(work) From 47fe83f5d0655bda8f5f03d4e285219d2958b5ce Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 24 Mar 2021 10:26:49 +0100 Subject: [PATCH 16/16] consensus/ethash: ensure ModeShared works with New --- consensus/ethash/ethash.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index fffbb67cc4be..1d23aa101f11 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -48,11 +48,7 @@ var ( two256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) // sharedEthash is a full instance that can be shared between multiple users. - sharedEthash = New(Config{ - CachesInMem: 3, - DatasetsInMem: 1, - PowMode: ModeNormal, - }, nil, false) + sharedEthash *Ethash // algorithmRevision is the data structure version used for file naming. algorithmRevision = 23 @@ -61,6 +57,15 @@ var ( dumpMagic = []uint32{0xbaddcafe, 0xfee1dead} ) +func init() { + sharedConfig := Config{ + PowMode: ModeNormal, + CachesInMem: 3, + DatasetsInMem: 1, + } + sharedEthash = New(sharedConfig, nil, false) +} + // isLittleEndian returns whether the local system is running in little or big // endian byte order. func isLittleEndian() bool { @@ -470,6 +475,9 @@ func New(config Config, notify []string, noverify bool) *Ethash { update: make(chan struct{}), hashrate: metrics.NewMeterForced(), } + if config.PowMode == ModeShared { + ethash.shared = sharedEthash + } ethash.remote = startRemoteSealer(ethash, notify, noverify) return ethash } @@ -477,15 +485,7 @@ func New(config Config, notify []string, noverify bool) *Ethash { // NewTester creates a small sized ethash PoW scheme useful only for testing // purposes. func NewTester(notify []string, noverify bool) *Ethash { - ethash := &Ethash{ - config: Config{PowMode: ModeTest, Log: log.Root()}, - caches: newlru("cache", 1, newCache), - datasets: newlru("dataset", 1, newDataset), - update: make(chan struct{}), - hashrate: metrics.NewMeterForced(), - } - ethash.remote = startRemoteSealer(ethash, notify, noverify) - return ethash + return New(Config{PowMode: ModeTest}, notify, noverify) } // NewFaker creates a ethash consensus engine with a fake PoW scheme that accepts