diff --git a/eth/handler.go b/eth/handler.go index 4ab17fb6c5b08..3a0986687d200 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -80,7 +80,7 @@ type HandlerConfig handlerConfig // node network handler. type handlerConfig struct { Database ethdb.Database // Database for direct sync insertions - Chain *core.BlockChain // Blockchain to serve data from + Chain eth.HandlerBlockchain // Blockchain to serve data from TxPool txPool // Transaction pool to propagate from Merger *consensus.Merger // The manager for eth1/2 transition Network uint64 // Network identifier to adfvertise @@ -91,6 +91,20 @@ type handlerConfig struct { Whitelist map[uint64]common.Hash // Hard coded whitelist for sync challenged } +type Handler handler + +func (h *Handler) BroadcastTransactions(txs types.Transactions) { + (*handler)(h).BroadcastTransactions(txs) +} + +func (h *Handler) PeerCount() int { + return h.peers.len() +} + +func (h *Handler) Start(maxPeers int) { + (*handler)(h).Start(maxPeers) +} + type handler struct { networkID uint64 forkFilter forkid.Filter // Fork ID filter, constant across the lifetime of the node @@ -103,7 +117,7 @@ type handler struct { database ethdb.Database txpool txPool - chain *core.BlockChain + chain eth.HandlerBlockchain maxPeers int downloader *downloader.Downloader diff --git a/eth/handler_eth.go b/eth/handler_eth.go index 828c13fd3bceb..7c6386b08a6ab 100644 --- a/eth/handler_eth.go +++ b/eth/handler_eth.go @@ -23,18 +23,19 @@ import ( "time" "github.com/blockcypher/go-ethereum/common" - "github.com/blockcypher/go-ethereum/core" "github.com/blockcypher/go-ethereum/core/types" "github.com/blockcypher/go-ethereum/eth/protocols/eth" "github.com/blockcypher/go-ethereum/p2p/enode" ) +type EthHandler ethHandler + // ethHandler implements the eth.Backend interface to handle the various network // packets that are sent as replies or broadcasts. type ethHandler handler -func (h *ethHandler) Chain() *core.BlockChain { return h.chain } -func (h *ethHandler) TxPool() eth.TxPool { return h.txpool } +func (h *ethHandler) Chain() eth.HandlerBlockchain { return h.chain } +func (h *ethHandler) TxPool() eth.TxPool { return h.txpool } // RunPeer is invoked when a peer joins on the `eth` protocol. func (h *ethHandler) RunPeer(peer *eth.Peer, hand eth.Handler) error { diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 18ebce5592b0b..55dc944dae2ae 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -49,7 +49,7 @@ type testEthHandler struct { txBroadcasts event.Feed } -func (h *testEthHandler) Chain() *core.BlockChain { panic("no backing chain") } +func (h *testEthHandler) Chain() eth.HandlerBlockchain { panic("no backing chain") } func (h *testEthHandler) TxPool() eth.TxPool { panic("no backing tx pool") } func (h *testEthHandler) AcceptTxs() bool { return true } func (h *testEthHandler) RunPeer(*eth.Peer, eth.Handler) error { panic("not used in tests") } diff --git a/eth/handler_snap.go b/eth/handler_snap.go index f9f2c299042a5..3e49f3beb2669 100644 --- a/eth/handler_snap.go +++ b/eth/handler_snap.go @@ -17,7 +17,7 @@ package eth import ( - "github.com/blockcypher/go-ethereum/core" + "github.com/blockcypher/go-ethereum/eth/protocols/eth" "github.com/blockcypher/go-ethereum/eth/protocols/snap" "github.com/blockcypher/go-ethereum/p2p/enode" ) @@ -26,7 +26,7 @@ import ( // packets that are sent as replies or broadcasts. type snapHandler handler -func (h *snapHandler) Chain() *core.BlockChain { return h.chain } +func (h *snapHandler) Chain() eth.HandlerBlockchain { return h.chain } // RunPeer is invoked when a peer joins on the `snap` protocol. func (h *snapHandler) RunPeer(peer *snap.Peer, hand snap.Handler) error { diff --git a/eth/protocols/eth/discovery.go b/eth/protocols/eth/discovery.go index 4fe067318562d..b8f225c4facfb 100644 --- a/eth/protocols/eth/discovery.go +++ b/eth/protocols/eth/discovery.go @@ -38,7 +38,7 @@ func (e enrEntry) ENRKey() string { // StartENRUpdater starts the `eth` ENR updater loop, which listens for chain // head events and updates the requested node record whenever a fork is passed. -func StartENRUpdater(chain *core.BlockChain, ln *enode.LocalNode) { +func StartENRUpdater(chain HandlerBlockchain, ln *enode.LocalNode) { var newHead = make(chan core.ChainHeadEvent, 10) sub := chain.SubscribeChainHeadEvent(newHead) @@ -58,7 +58,7 @@ func StartENRUpdater(chain *core.BlockChain, ln *enode.LocalNode) { } // currentENREntry constructs an `eth` ENR entry based on the current state of the chain. -func currentENREntry(chain *core.BlockChain) *enrEntry { +func currentENREntry(chain HandlerBlockchain) *enrEntry { return &enrEntry{ ForkID: forkid.NewID(chain.Config(), chain.Genesis().Hash(), chain.CurrentHeader().Number.Uint64()), } diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 3e0ed02750b17..644fa04638920 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -22,13 +22,18 @@ import ( "time" "github.com/blockcypher/go-ethereum/common" + "github.com/blockcypher/go-ethereum/consensus" "github.com/blockcypher/go-ethereum/core" + "github.com/blockcypher/go-ethereum/core/state" + "github.com/blockcypher/go-ethereum/core/state/snapshot" "github.com/blockcypher/go-ethereum/core/types" + "github.com/blockcypher/go-ethereum/event" "github.com/blockcypher/go-ethereum/metrics" "github.com/blockcypher/go-ethereum/p2p" "github.com/blockcypher/go-ethereum/p2p/enode" "github.com/blockcypher/go-ethereum/p2p/enr" "github.com/blockcypher/go-ethereum/params" + "github.com/blockcypher/go-ethereum/rlp" ) const ( @@ -55,6 +60,61 @@ const ( maxReceiptsServe = 1024 ) +type HandlerBlockchain interface { + SetHead(head uint64) error + CurrentBlock() *types.Block + CurrentFastBlock() *types.Block + Genesis() *types.Block + + HasBlock(hash common.Hash, number uint64) bool + HasFastBlock(hash common.Hash, number uint64) bool + GetBlock(hash common.Hash, number uint64) *types.Block + GetBlockByHash(hash common.Hash) *types.Block + StopInsert() + InsertBlockWithoutSetHead(block *types.Block) error + InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts, ancientLimit uint64) (int, error) + + SetTxLookupLimit(limit uint64) + TxLookupLimit() uint64 + + InsertChain(chain types.Blocks) (int, error) + + InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) + CurrentHeader() *types.Header + GetTd(hash common.Hash, number uint64) *big.Int + GetHeader(hash common.Hash, number uint64) *types.Header + GetHeaderByHash(hash common.Hash) *types.Header + GetHeadersFrom(number, count uint64) []rlp.RawValue + HasHeader(hash common.Hash, number uint64) bool + GetHeaderByNumber(number uint64) *types.Header + + Config() *params.ChainConfig + Engine() consensus.Engine + + // Additionnal func for particular handler + // required by snap + SnapSyncCommitHead(common.Hash) error + Snapshots() *snapshot.Tree + ContractCode(hash common.Hash) ([]byte, error) + StateCache() state.Database + + // required by discovery.go + SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription + + // required by eth/handlers.go + GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) + GetBodyRLP(hash common.Hash) rlp.RawValue + TrieNode(hash common.Hash) ([]byte, error) + ContractCodeWithPrefix(hash common.Hash) ([]byte, error) + GetReceiptsByHash(hash common.Hash) types.Receipts + + // required for eth/handler_test.go + GetBlockByNumber(number uint64) *types.Block + GetCanonicalHash(number uint64) common.Hash + StateAt(root common.Hash) (*state.StateDB, error) + Stop() +} + // Handler is a callback to invoke from an outside runner after the boilerplate // exchanges have passed. type Handler func(peer *Peer) error @@ -63,7 +123,7 @@ type Handler func(peer *Peer) error // callback methods to invoke on remote deliveries. type Backend interface { // Chain retrieves the blockchain object to serve data. - Chain() *core.BlockChain + Chain() HandlerBlockchain // TxPool retrieves the transaction pool object to serve data. TxPool() TxPool @@ -135,7 +195,7 @@ type NodeInfo struct { } // nodeInfo retrieves some `eth` protocol metadata about the running host node. -func nodeInfo(chain *core.BlockChain, network uint64) *NodeInfo { +func nodeInfo(chain HandlerBlockchain, network uint64) *NodeInfo { head := chain.CurrentBlock() return &NodeInfo{ Network: network, diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 2f9d422ebed24..bcb084af34ec6 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -49,7 +49,7 @@ var ( // in the `eth` protocol without actually doing any data processing. type testBackend struct { db ethdb.Database - chain *core.BlockChain + chain HandlerBlockchain txpool *core.TxPool } @@ -90,8 +90,8 @@ func (b *testBackend) close() { b.chain.Stop() } -func (b *testBackend) Chain() *core.BlockChain { return b.chain } -func (b *testBackend) TxPool() TxPool { return b.txpool } +func (b *testBackend) Chain() HandlerBlockchain { return b.chain } +func (b *testBackend) TxPool() TxPool { return b.txpool } func (b *testBackend) RunPeer(peer *Peer, handler Handler) error { // Normally the backend would do peer mainentance and handshakes. All that diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index 67517e80013aa..9f10c4deec65d 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -21,7 +21,6 @@ import ( "fmt" "github.com/blockcypher/go-ethereum/common" - "github.com/blockcypher/go-ethereum/core" "github.com/blockcypher/go-ethereum/core/types" "github.com/blockcypher/go-ethereum/log" "github.com/blockcypher/go-ethereum/rlp" @@ -41,7 +40,7 @@ func handleGetBlockHeaders66(backend Backend, msg Decoder, peer *Peer) error { // ServiceGetBlockHeadersQuery assembles the response to a header query. It is // exposed to allow external packages to test protocol behavior. -func ServiceGetBlockHeadersQuery(chain *core.BlockChain, query *GetBlockHeadersPacket, peer *Peer) []rlp.RawValue { +func ServiceGetBlockHeadersQuery(chain HandlerBlockchain, query *GetBlockHeadersPacket, peer *Peer) []rlp.RawValue { if query.Skip == 0 { // The fast path: when the request is for a contiguous segment of headers. return serviceContiguousBlockHeaderQuery(chain, query) @@ -50,7 +49,7 @@ func ServiceGetBlockHeadersQuery(chain *core.BlockChain, query *GetBlockHeadersP } } -func serviceNonContiguousBlockHeaderQuery(chain *core.BlockChain, query *GetBlockHeadersPacket, peer *Peer) []rlp.RawValue { +func serviceNonContiguousBlockHeaderQuery(chain HandlerBlockchain, query *GetBlockHeadersPacket, peer *Peer) []rlp.RawValue { hashMode := query.Origin.Hash != (common.Hash{}) first := true maxNonCanonical := uint64(100) @@ -139,7 +138,7 @@ func serviceNonContiguousBlockHeaderQuery(chain *core.BlockChain, query *GetBloc return headers } -func serviceContiguousBlockHeaderQuery(chain *core.BlockChain, query *GetBlockHeadersPacket) []rlp.RawValue { +func serviceContiguousBlockHeaderQuery(chain HandlerBlockchain, query *GetBlockHeadersPacket) []rlp.RawValue { count := query.Amount if count > maxHeadersServe { count = maxHeadersServe @@ -214,7 +213,7 @@ func handleGetBlockBodies66(backend Backend, msg Decoder, peer *Peer) error { // ServiceGetBlockBodiesQuery assembles the response to a body query. It is // exposed to allow external packages to test protocol behavior. -func ServiceGetBlockBodiesQuery(chain *core.BlockChain, query GetBlockBodiesPacket) []rlp.RawValue { +func ServiceGetBlockBodiesQuery(chain HandlerBlockchain, query GetBlockBodiesPacket) []rlp.RawValue { // Gather blocks until the fetch or network limits is reached var ( bytes int @@ -245,7 +244,7 @@ func handleGetNodeData66(backend Backend, msg Decoder, peer *Peer) error { // ServiceGetNodeDataQuery assembles the response to a node data query. It is // exposed to allow external packages to test protocol behavior. -func ServiceGetNodeDataQuery(chain *core.BlockChain, query GetNodeDataPacket) [][]byte { +func ServiceGetNodeDataQuery(chain HandlerBlockchain, query GetNodeDataPacket) [][]byte { // Gather state data until the fetch or network limits is reached var ( bytes int @@ -282,7 +281,7 @@ func handleGetReceipts66(backend Backend, msg Decoder, peer *Peer) error { // ServiceGetReceiptsQuery assembles the response to a receipt query. It is // exposed to allow external packages to test protocol behavior. -func ServiceGetReceiptsQuery(chain *core.BlockChain, query GetReceiptsPacket) []rlp.RawValue { +func ServiceGetReceiptsQuery(chain HandlerBlockchain, query GetReceiptsPacket) []rlp.RawValue { // Gather state data until the fetch or network limits is reached var ( bytes int diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index e4ccf02b4c82d..92feb97a8dd8c 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -22,8 +22,8 @@ import ( "time" "github.com/blockcypher/go-ethereum/common" - "github.com/blockcypher/go-ethereum/core" "github.com/blockcypher/go-ethereum/core/types" + "github.com/blockcypher/go-ethereum/eth/protocols/eth" "github.com/blockcypher/go-ethereum/light" "github.com/blockcypher/go-ethereum/log" "github.com/blockcypher/go-ethereum/metrics" @@ -65,7 +65,7 @@ type Handler func(peer *Peer) error // callback methods to invoke on remote deliveries. type Backend interface { // Chain retrieves the blockchain object to serve data. - Chain() *core.BlockChain + Chain() eth.HandlerBlockchain // RunPeer is invoked when a peer joins on the `eth` protocol. The handler // should do any peer maintenance work, handshakes and validations. If all @@ -280,7 +280,7 @@ func HandleMessage(backend Backend, peer *Peer) error { // ServiceGetAccountRangeQuery assembles the response to an account range query. // It is exposed to allow external packages to test protocol behavior. -func ServiceGetAccountRangeQuery(chain *core.BlockChain, req *GetAccountRangePacket) ([]*AccountData, [][]byte) { +func ServiceGetAccountRangeQuery(chain eth.HandlerBlockchain, req *GetAccountRangePacket) ([]*AccountData, [][]byte) { if req.Bytes > softResponseLimit { req.Bytes = softResponseLimit } @@ -340,7 +340,7 @@ func ServiceGetAccountRangeQuery(chain *core.BlockChain, req *GetAccountRangePac return accounts, proofs } -func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesPacket) ([][]*StorageData, [][]byte) { +func ServiceGetStorageRangesQuery(chain eth.HandlerBlockchain, req *GetStorageRangesPacket) ([][]*StorageData, [][]byte) { if req.Bytes > softResponseLimit { req.Bytes = softResponseLimit } @@ -450,7 +450,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP // ServiceGetByteCodesQuery assembles the response to a byte codes query. // It is exposed to allow external packages to test protocol behavior. -func ServiceGetByteCodesQuery(chain *core.BlockChain, req *GetByteCodesPacket) [][]byte { +func ServiceGetByteCodesQuery(chain eth.HandlerBlockchain, req *GetByteCodesPacket) [][]byte { if req.Bytes > softResponseLimit { req.Bytes = softResponseLimit } @@ -480,7 +480,7 @@ func ServiceGetByteCodesQuery(chain *core.BlockChain, req *GetByteCodesPacket) [ // ServiceGetTrieNodesQuery assembles the response to a trie nodes query. // It is exposed to allow external packages to test protocol behavior. -func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, start time.Time) ([][]byte, error) { +func ServiceGetTrieNodesQuery(chain eth.HandlerBlockchain, req *GetTrieNodesPacket, start time.Time) ([][]byte, error) { if req.Bytes > softResponseLimit { req.Bytes = softResponseLimit } @@ -562,6 +562,6 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s type NodeInfo struct{} // nodeInfo retrieves some `snap` protocol metadata about the running host node. -func nodeInfo(chain *core.BlockChain) *NodeInfo { +func nodeInfo(chain eth.HandlerBlockchain) *NodeInfo { return &NodeInfo{} } diff --git a/tests/fuzzers/snap/fuzz_handler.go b/tests/fuzzers/snap/fuzz_handler.go index 08ec6923299a2..dde39ad325245 100644 --- a/tests/fuzzers/snap/fuzz_handler.go +++ b/tests/fuzzers/snap/fuzz_handler.go @@ -28,6 +28,7 @@ import ( "github.com/blockcypher/go-ethereum/core" "github.com/blockcypher/go-ethereum/core/rawdb" "github.com/blockcypher/go-ethereum/core/vm" + "github.com/blockcypher/go-ethereum/eth/protocols/eth" "github.com/blockcypher/go-ethereum/eth/protocols/snap" "github.com/blockcypher/go-ethereum/p2p" "github.com/blockcypher/go-ethereum/p2p/enode" @@ -87,10 +88,10 @@ func getChain() *core.BlockChain { } type dummyBackend struct { - chain *core.BlockChain + chain eth.HandlerBlockchain } -func (d *dummyBackend) Chain() *core.BlockChain { return d.chain } +func (d *dummyBackend) Chain() eth.HandlerBlockchain { return d.chain } func (d *dummyBackend) RunPeer(*snap.Peer, snap.Handler) error { return nil } func (d *dummyBackend) PeerInfo(enode.ID) interface{} { return "Foo" } func (d *dummyBackend) Handle(*snap.Peer, snap.Packet) error { return nil }