Activate wire protocol eth/66 (#993)

* Activate wire protocol eth/66

and:
 Disentangle protocol_eth66.nim from import sections

why:
  Importing the protocol_eth66 module is not necessary. There is
  no need to know too many details of the underlying wire protocol. All
  that is needed will be exported by blockchain_sync.nim.

* fixes, and rebase

* Update nimbus/p2p/blockchain_sync.nim

Co-authored-by: Kim De Mey <kim.demey@gmail.com>

* Fixes and rebase

Co-authored-by: Kim De Mey <kim.demey@gmail.com>
This commit is contained in:
Jordan Hrycaj 2022-03-21 17:12:07 +00:00 committed by GitHub
parent 74127644db
commit 046c97f18b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 69 additions and 27 deletions

View File

@ -10,7 +10,7 @@
import import
std/[os, json], std/[os, json],
eth/[p2p, trie/db], ../../../nimbus/db/db_chain, eth/[p2p, trie/db], ../../../nimbus/db/db_chain,
../../../nimbus/sync/protocol_eth65, ../../../nimbus/sync/protocol_ethxx,
../../../nimbus/[genesis, config, conf_utils, context], ../../../nimbus/[genesis, config, conf_utils, context],
../../../nimbus/graphql/ethapi, ../../../tests/test_helpers, ../../../nimbus/graphql/ethapi, ../../../tests/test_helpers,
../../../nimbus/utils/tx_pool, ../../../nimbus/utils/tx_pool,

View File

@ -15,7 +15,7 @@ import
stew/results, stew/results,
chronos, json_rpc/[rpcserver, rpcclient], chronos, json_rpc/[rpcserver, rpcclient],
../../../nimbus/db/db_chain, ../../../nimbus/db/db_chain,
../../../nimbus/sync/protocol_eth65, ../../../nimbus/p2p/protocol_ethxx,
../../../nimbus/[config, context, genesis], ../../../nimbus/[config, context, genesis],
../../../nimbus/rpc/[common, p2p, debug], ../../../nimbus/rpc/[common, p2p, debug],
../../../tests/test_helpers, ../../../tests/test_helpers,

View File

@ -17,9 +17,9 @@ import
eth/common as eth_common, eth/p2p as eth_p2p, eth/common as eth_common, eth/p2p as eth_p2p,
chronos, json_rpc/rpcserver, chronicles, chronos, json_rpc/rpcserver, chronicles,
eth/p2p/rlpx_protocols/les_protocol, eth/p2p/rlpx_protocols/les_protocol,
./sync/protocol_ethxx,
./p2p/blockchain_sync, eth/net/nat, eth/p2p/peer_pool, ./p2p/blockchain_sync, eth/net/nat, eth/p2p/peer_pool,
./p2p/clique/[clique_desc, clique_sealer], ./p2p/clique/[clique_desc, clique_sealer],
./sync/protocol_eth65,
config, genesis, rpc/[common, p2p, debug, engine_api], p2p/chain, config, genesis, rpc/[common, p2p, debug, engine_api], p2p/chain,
eth/trie/db, metrics, metrics/[chronos_httpserver, chronicles_support], eth/trie/db, metrics, metrics/[chronos_httpserver, chronicles_support],
graphql/ethapi, context, utils/tx_pool, graphql/ethapi, context, utils/tx_pool,

View File

@ -8,9 +8,11 @@
import import
std/[sets, options, random, hashes, sequtils], std/[sets, options, random, hashes, sequtils],
chronos, chronicles, chronos, chronicles,
../sync/protocol_ethxx,
eth/common/eth_types, eth/common/eth_types,
eth/[p2p, p2p/private/p2p_types, p2p/rlpx, p2p/peer_pool], eth/[p2p, p2p/private/p2p_types, p2p/rlpx, p2p/peer_pool]
../sync/protocol_eth65
{.push raises:[Defect].}
const const
minPeersToStartSync* = 2 # Wait for consensus of at least this minPeersToStartSync* = 2 # Wait for consensus of at least this
@ -22,6 +24,9 @@ type
syncNotEnoughPeers syncNotEnoughPeers
syncTimeOut syncTimeOut
BlockchainSyncDefect* = object of Defect
## Catch and relay exception
WantedBlocksState = enum WantedBlocksState = enum
Initial, Initial,
Requested, Requested,
@ -44,6 +49,17 @@ type
trustedPeers: HashSet[Peer] trustedPeers: HashSet[Peer]
hasOutOfOrderBlocks: bool hasOutOfOrderBlocks: bool
template catchException(info: string; code: untyped) =
try:
code
except CatchableError as e:
raise (ref CatchableError)(msg: e.msg)
except Defect as e:
raise (ref Defect)(msg: e.msg)
except Exception as e:
raise newException(
BlockchainSyncDefect, info & "(): " & $e.name & " -- " & e.msg)
proc hash*(p: Peer): Hash = hash(cast[pointer](p)) proc hash*(p: Peer): Hash = hash(cast[pointer](p))
proc endIndex(b: WantedBlocks): BlockNumber = proc endIndex(b: WantedBlocks): BlockNumber =
@ -89,13 +105,15 @@ proc availableWorkItem(ctx: SyncContext): int =
# Create new work item when queue was increased, reset when selected work item # Create new work item when queue was increased, reset when selected work item
# is at Persisted state. # is at Persisted state.
var numBlocks = (ctx.endBlockNumber - nextRequestedBlock).toInt var numBlocks = (ctx.endBlockNumber - nextRequestedBlock).truncate(int)
if numBlocks > maxHeadersFetch: if numBlocks > maxHeadersFetch:
numBlocks = maxHeadersFetch numBlocks = maxHeadersFetch
ctx.workQueue[result] = WantedBlocks(startIndex: nextRequestedBlock, numBlocks: numBlocks.uint, state: Initial) ctx.workQueue[result] = WantedBlocks(startIndex: nextRequestedBlock, numBlocks: numBlocks.uint, state: Initial)
proc persistWorkItem(ctx: SyncContext, wi: var WantedBlocks): ValidationResult = proc persistWorkItem(ctx: SyncContext, wi: var WantedBlocks): ValidationResult
result = ctx.chain.persistBlocks(wi.headers, wi.bodies) {.gcsafe, raises:[Defect,CatchableError].} =
catchException("persistBlocks"):
result = ctx.chain.persistBlocks(wi.headers, wi.bodies)
case result case result
of ValidationResult.OK: of ValidationResult.OK:
ctx.finalizedBlock = wi.endIndex ctx.finalizedBlock = wi.endIndex
@ -106,7 +124,8 @@ proc persistWorkItem(ctx: SyncContext, wi: var WantedBlocks): ValidationResult =
wi.headers = @[] wi.headers = @[]
wi.bodies = @[] wi.bodies = @[]
proc persistPendingWorkItems(ctx: SyncContext): (int, ValidationResult) = proc persistPendingWorkItems(ctx: SyncContext): (int, ValidationResult)
{.gcsafe, raises:[Defect,CatchableError].} =
var nextStartIndex = ctx.finalizedBlock + 1 var nextStartIndex = ctx.finalizedBlock + 1
var keepRunning = true var keepRunning = true
var hasOutOfOrderBlocks = false var hasOutOfOrderBlocks = false
@ -134,7 +153,8 @@ proc persistPendingWorkItems(ctx: SyncContext): (int, ValidationResult) =
ctx.hasOutOfOrderBlocks = hasOutOfOrderBlocks ctx.hasOutOfOrderBlocks = hasOutOfOrderBlocks
proc returnWorkItem(ctx: SyncContext, workItem: int): ValidationResult = proc returnWorkItem(ctx: SyncContext, workItem: int): ValidationResult
{.gcsafe, raises:[Defect,CatchableError].} =
let wi = addr ctx.workQueue[workItem] let wi = addr ctx.workQueue[workItem]
let askedBlocks = wi.numBlocks.int let askedBlocks = wi.numBlocks.int
let receivedBlocks = wi.headers.len let receivedBlocks = wi.headers.len
@ -172,7 +192,8 @@ proc returnWorkItem(ctx: SyncContext, workItem: int): ValidationResult =
receivedBlocks receivedBlocks
return ValidationResult.Error return ValidationResult.Error
proc newSyncContext(chain: AbstractChainDB, peerPool: PeerPool): SyncContext = proc newSyncContext(chain: AbstractChainDB, peerPool: PeerPool): SyncContext
{.gcsafe, raises:[Defect,CatchableError].} =
new result new result
result.chain = chain result.chain = chain
result.peerPool = peerPool result.peerPool = peerPool
@ -193,7 +214,7 @@ proc getBestBlockNumber(p: Peer): Future[BlockNumber] {.async.} =
reverse: true) reverse: true)
tracePacket ">> Sending eth.GetBlockHeaders (0x03)", peer=p, tracePacket ">> Sending eth.GetBlockHeaders (0x03)", peer=p,
startBlock=request.startBlock.hash, max=request.maxResults startBlock=request.startBlock.hash.toHex, max=request.maxResults
let latestBlock = await p.getBlockHeaders(request) let latestBlock = await p.getBlockHeaders(request)
if latestBlock.isSome: if latestBlock.isSome:
@ -324,7 +345,7 @@ proc peersAgreeOnChain(a, b: Peer): Future[bool] {.async.} =
reverse: true) reverse: true)
tracePacket ">> Sending eth.GetBlockHeaders (0x03)", peer=a, tracePacket ">> Sending eth.GetBlockHeaders (0x03)", peer=a,
startBlock=request.startBlock.hash, max=request.maxResults startBlock=request.startBlock.hash.toHex, max=request.maxResults
let latestBlock = await a.getBlockHeaders(request) let latestBlock = await a.getBlockHeaders(request)
result = latestBlock.isSome and latestBlock.get.headers.len > 0 result = latestBlock.isSome and latestBlock.get.headers.len > 0

View File

@ -6,9 +6,9 @@
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) # * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except according to those terms. # at your option. This file may not be copied, modified, or distributed except according to those terms.
## This module implements Ethereum Wire Protocol version 65, `eth/65`. ## This module implements Ethereum Wire Protocol version 66, `eth/66`.
## Specification: ## Specification:
## https://github.com/ethereum/devp2p/blob/master/caps/eth.md ## `eth/66 <https://github.com/ethereum/devp2p/blob/master/caps/eth.md>`_
import import
chronos, stint, chronicles, stew/byteutils, macros, chronos, stint, chronicles, stew/byteutils, macros,
@ -26,6 +26,10 @@ type
forkHash: array[4, byte] # The RLP encoding must be exactly 4 bytes. forkHash: array[4, byte] # The RLP encoding must be exactly 4 bytes.
forkNext: BlockNumber # The RLP encoding must be variable-length forkNext: BlockNumber # The RLP encoding must be variable-length
NewBlockAndTotalDiff* = object
ethBlock: EthBlock
totalDifficulty: DifficultyInt
PeerState = ref object PeerState = ref object
initialized*: bool initialized*: bool
bestBlockHash*: KeccakHash bestBlockHash*: KeccakHash
@ -40,7 +44,7 @@ const
maxBodiesFetch* = 128 maxBodiesFetch* = 128
maxReceiptsFetch* = 256 maxReceiptsFetch* = 256
maxHeadersFetch* = 192 maxHeadersFetch* = 192
ethVersion = 65 ethVersion* = 66
func toHex*(x: KeccakHash): string = x.data.toHex func toHex*(x: KeccakHash): string = x.data.toHex
macro tracePacket*(msg: static[string], args: varargs[untyped]) = macro tracePacket*(msg: static[string], args: varargs[untyped]) =
@ -50,7 +54,7 @@ macro tracePacket*(msg: static[string], args: varargs[untyped]) =
p2pProtocol eth(version = ethVersion, p2pProtocol eth(version = ethVersion,
peerState = PeerState, peerState = PeerState,
useRequestIds = false): useRequestIds = true):
onPeerConnected do (peer: Peer): onPeerConnected do (peer: Peer):
let let
@ -60,8 +64,7 @@ p2pProtocol eth(version = ethVersion,
chainForkId = chain.getForkId(bestBlock.blockNumber) chainForkId = chain.getForkId(bestBlock.blockNumber)
forkId = ForkId( forkId = ForkId(
forkHash: chainForkId.crc.toBytesBe, forkHash: chainForkId.crc.toBytesBe,
forkNext: chainForkId.nextFork.u256, forkNext: chainForkId.nextFork.u256)
)
tracePacket ">> Sending eth.Status (0x00) [eth/" & $ethVersion & "]", tracePacket ">> Sending eth.Status (0x00) [eth/" & $ethVersion & "]",
peer, td=bestBlock.difficulty, peer, td=bestBlock.difficulty,
@ -184,7 +187,8 @@ p2pProtocol eth(version = ethVersion,
# because either `p2pProtocol` or RLPx doesn't work with an alias.) # because either `p2pProtocol` or RLPx doesn't work with an alias.)
tracePacket "<< Discarding eth.NewBlock (0x07)", tracePacket "<< Discarding eth.NewBlock (0x07)",
peer, totalDifficulty, peer, totalDifficulty,
blockNumber=bh.header.blockNumber, blockDifficulty=bh.header.difficulty blockNumber = bh.header.blockNumber,
blockDifficulty = bh.header.difficulty
discard discard
# User message 0x08: NewPooledTransactionHashes. # User message 0x08: NewPooledTransactionHashes.

View File

@ -0,0 +1,12 @@
# Nimbus
# Copyright (c) 2018-2021 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at
# https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at
# https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed
# except according to those terms.
import ./protocol_eth66
export protocol_eth66

5
tests/graphql/README.md Normal file
View File

@ -0,0 +1,5 @@
per protocool folders apply, e.g.
- eth65/queries.toml (obsoleted *eth65* test specs)
- eth66/queries.toml
- ...

View File

@ -486,7 +486,7 @@ mutation {
""" """
result = """ result = """
{ {
"protocolVersion":65 "protocolVersion":66
} }
""" """

View File

@ -12,7 +12,7 @@ import
stew/byteutils, unittest2, stew/byteutils, unittest2,
eth/[p2p, common, trie/db, rlp], eth/[p2p, common, trie/db, rlp],
graphql, ../nimbus/graphql/ethapi, graphql/test_common, graphql, ../nimbus/graphql/ethapi, graphql/test_common,
../nimbus/sync/protocol_eth65, ../nimbus/sync/protocol_ethxx,
../nimbus/[genesis, config, chain_config, context], ../nimbus/[genesis, config, chain_config, context],
../nimbus/db/[db_chain], ../nimbus/db/[db_chain],
../nimbus/p2p/chain, ./test_helpers, ../nimbus/p2p/chain, ./test_helpers,
@ -25,7 +25,7 @@ type
uncles: seq[BlockHeader] uncles: seq[BlockHeader]
const const
caseFolder = "tests" / "graphql" caseFolder = "tests" / "graphql" / "eth" & $ethVersion
dataFolder = "tests" / "fixtures" / "eth_tests" / "BlockchainTests" / "ValidBlocks" / "bcUncleTest" dataFolder = "tests" / "fixtures" / "eth_tests" / "BlockchainTests" / "ValidBlocks" / "bcUncleTest"
proc toBlock(n: JsonNode, key: string): EthBlock = proc toBlock(n: JsonNode, key: string): EthBlock =

View File

@ -12,12 +12,12 @@ import
unittest2, nimcrypto, eth/common as eth_common, unittest2, nimcrypto, eth/common as eth_common,
json_rpc/[rpcserver, rpcclient], web3/[conversions, engine_api_types], json_rpc/[rpcserver, rpcclient], web3/[conversions, engine_api_types],
eth/[trie/db, p2p/private/p2p_types], eth/[trie/db, p2p/private/p2p_types],
../nimbus/sync/protocol_eth65, ../nimbus/sync/protocol_ethxx,
../nimbus/rpc/[common, p2p, hexstrings, rpc_types, rpc_utils, engine_api], ../nimbus/rpc/[common, p2p, hexstrings, rpc_types, rpc_utils, engine_api],
../nimbus/db/[db_chain], ../nimbus/db/[db_chain],
../nimbus/[chain_config, config, context, genesis, sealer], ../nimbus/[chain_config, config, context, genesis, sealer],
../nimbus/utils/[tx_pool], ../nimbus/utils/[tx_pool],
../nimbus/p2p/[chain], ../nimbus/p2p/chain,
../nimbus/merge/mergetypes, ../nimbus/merge/mergetypes,
./test_helpers ./test_helpers

View File

@ -14,8 +14,8 @@ import
../nimbus/[constants, config, genesis, utils, transaction, ../nimbus/[constants, config, genesis, utils, transaction,
vm_state, vm_types], vm_state, vm_types],
../nimbus/db/[accounts_cache, db_chain], ../nimbus/db/[accounts_cache, db_chain],
../nimbus/sync/protocol_ethxx,
../nimbus/p2p/[chain, executor, executor/executor_helpers], ../nimbus/p2p/[chain, executor, executor/executor_helpers],
../nimbus/sync/protocol_eth65,
../nimbus/utils/[difficulty, tx_pool], ../nimbus/utils/[difficulty, tx_pool],
../nimbus/[context, chain_config], ../nimbus/[context, chain_config],
./test_helpers, ./macro_assembler ./test_helpers, ./macro_assembler
@ -217,7 +217,7 @@ proc rpcMain*() =
# same expression as the client can hide issues when the value is wrong # same expression as the client can hide issues when the value is wrong
# in both places. When the expected value genuinely changes, it'll be # in both places. When the expected value genuinely changes, it'll be
# obvious. Just change this number. # obvious. Just change this number.
check res == "65" check res == $ethVersion
test "eth_syncing": test "eth_syncing":
let res = await client.eth_syncing() let res = await client.eth_syncing()