2019-02-05 15:40:29 +00:00
|
|
|
#
|
|
|
|
# Ethereum P2P
|
|
|
|
# (c) Copyright 2018
|
|
|
|
# Status Research & Development GmbH
|
|
|
|
#
|
|
|
|
# Licensed under either of
|
|
|
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
|
|
|
# MIT license (LICENSE-MIT)
|
|
|
|
#
|
|
|
|
|
|
|
|
## This module implements the Ethereum Wire Protocol:
|
|
|
|
## https://github.com/ethereum/wiki/wiki/Ethereum-Wire-Protocol
|
|
|
|
|
|
|
|
import
|
2021-04-06 11:33:24 +00:00
|
|
|
chronos, stint, chronicles,
|
|
|
|
../../rlp, ../../common/eth_types, ../../p2p,
|
|
|
|
../rlpx, ../private/p2p_types, ../blockchain_utils
|
2019-02-05 15:40:29 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
NewBlockHashesAnnounce* = object
|
|
|
|
hash: KeccakHash
|
|
|
|
number: uint
|
|
|
|
|
|
|
|
NewBlockAnnounce* = object
|
|
|
|
header*: BlockHeader
|
Remove `{.rlpInline.}` which was never really implemented
For a long time this caused invalid RLP parsing of `NewBlock` messages in the
`eth` protocol.
The `rlpInline` pragma was accepted but had no effect. We could implemented
it, but it doesn't seem worth doing, with tests etc, as there's only one user
which has been fixed another way.
With `NewBlock`, whenever a peer sent us `NewBlock`, we'd get an RLP decoding
error, and disconnected the peer thinking it was the peer's error.
These messages are sent often by good peers, so whenever we connected to a
really good peer, we'd end up disconnecting within a minute due to this. This
went unnoticed for years, as we stayed connected to old peers which have no new
blocks, and we weren't looking at peer quality, disconnect reasons or real-time
blockchain updates anyway.
Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-07-28 00:55:58 +00:00
|
|
|
txs*: seq[Transaction]
|
|
|
|
uncles*: seq[BlockHeader]
|
2019-02-05 15:40:29 +00:00
|
|
|
|
|
|
|
PeerState = ref object
|
|
|
|
initialized*: bool
|
|
|
|
bestBlockHash*: KeccakHash
|
|
|
|
bestDifficulty*: DifficultyInt
|
|
|
|
|
|
|
|
const
|
|
|
|
maxStateFetch* = 384
|
|
|
|
maxBodiesFetch* = 128
|
|
|
|
maxReceiptsFetch* = 256
|
|
|
|
maxHeadersFetch* = 192
|
|
|
|
protocolVersion* = 63
|
|
|
|
|
|
|
|
p2pProtocol eth(version = protocolVersion,
|
|
|
|
peerState = PeerState,
|
|
|
|
useRequestIds = false):
|
|
|
|
|
|
|
|
onPeerConnected do (peer: Peer):
|
|
|
|
let
|
|
|
|
network = peer.network
|
|
|
|
chain = network.chain
|
|
|
|
bestBlock = chain.getBestBlockHeader
|
|
|
|
|
2019-05-19 18:05:02 +00:00
|
|
|
let m = await peer.status(protocolVersion,
|
|
|
|
network.networkId,
|
|
|
|
bestBlock.difficulty,
|
|
|
|
bestBlock.blockHash,
|
|
|
|
chain.genesisHash,
|
|
|
|
timeout = chronos.seconds(10))
|
2019-02-05 15:40:29 +00:00
|
|
|
|
|
|
|
if m.networkId == network.networkId and m.genesisHash == chain.genesisHash:
|
|
|
|
trace "suitable peer", peer
|
|
|
|
else:
|
|
|
|
raise newException(UselessPeerError, "Eth handshake params mismatch")
|
|
|
|
peer.state.initialized = true
|
|
|
|
peer.state.bestDifficulty = m.totalDifficulty
|
|
|
|
peer.state.bestBlockHash = m.bestHash
|
|
|
|
|
2019-05-19 18:05:02 +00:00
|
|
|
handshake:
|
|
|
|
proc status(peer: Peer,
|
|
|
|
protocolVersion: uint,
|
2021-02-13 08:41:09 +00:00
|
|
|
networkId: NetworkId,
|
2019-05-19 18:05:02 +00:00
|
|
|
totalDifficulty: DifficultyInt,
|
|
|
|
bestHash: KeccakHash,
|
|
|
|
genesisHash: KeccakHash)
|
2019-02-05 15:40:29 +00:00
|
|
|
|
2021-12-20 12:14:50 +00:00
|
|
|
proc newBlockHashes(peer: Peer, hashes: openArray[NewBlockHashesAnnounce]) =
|
2019-02-05 15:40:29 +00:00
|
|
|
discard
|
|
|
|
|
2021-12-20 12:14:50 +00:00
|
|
|
proc transactions(peer: Peer, transactions: openArray[Transaction]) =
|
2019-02-05 15:40:29 +00:00
|
|
|
discard
|
|
|
|
|
|
|
|
requestResponse:
|
|
|
|
proc getBlockHeaders(peer: Peer, request: BlocksRequest) {.gcsafe.} =
|
|
|
|
if request.maxResults > uint64(maxHeadersFetch):
|
|
|
|
await peer.disconnect(BreachOfProtocol)
|
|
|
|
return
|
|
|
|
|
2019-03-11 09:22:06 +00:00
|
|
|
await response.send(peer.network.chain.getBlockHeaders(request))
|
2019-02-05 15:40:29 +00:00
|
|
|
|
2021-12-20 12:14:50 +00:00
|
|
|
proc blockHeaders(p: Peer, headers: openArray[BlockHeader])
|
2019-02-05 15:40:29 +00:00
|
|
|
|
|
|
|
requestResponse:
|
2021-12-20 12:14:50 +00:00
|
|
|
proc getBlockBodies(peer: Peer, hashes: openArray[KeccakHash]) {.gcsafe.} =
|
2019-02-05 15:40:29 +00:00
|
|
|
if hashes.len > maxBodiesFetch:
|
|
|
|
await peer.disconnect(BreachOfProtocol)
|
|
|
|
return
|
|
|
|
|
2019-07-08 11:15:50 +00:00
|
|
|
await response.send(peer.network.chain.getBlockBodies(hashes))
|
2019-02-05 15:40:29 +00:00
|
|
|
|
2021-12-20 12:14:50 +00:00
|
|
|
proc blockBodies(peer: Peer, blocks: openArray[BlockBody])
|
2019-02-05 15:40:29 +00:00
|
|
|
|
|
|
|
proc newBlock(peer: Peer, bh: NewBlockAnnounce, totalDifficulty: DifficultyInt) =
|
|
|
|
discard
|
|
|
|
|
|
|
|
nextID 13
|
|
|
|
|
|
|
|
requestResponse:
|
2021-12-20 12:14:50 +00:00
|
|
|
proc getNodeData(peer: Peer, hashes: openArray[KeccakHash]) =
|
2019-03-11 09:22:06 +00:00
|
|
|
await response.send(peer.network.chain.getStorageNodes(hashes))
|
2019-02-05 15:40:29 +00:00
|
|
|
|
2021-12-20 12:14:50 +00:00
|
|
|
proc nodeData(peer: Peer, data: openArray[Blob])
|
2019-02-05 15:40:29 +00:00
|
|
|
|
|
|
|
requestResponse:
|
2021-12-20 12:14:50 +00:00
|
|
|
proc getReceipts(peer: Peer, hashes: openArray[KeccakHash]) = discard
|
2019-06-13 13:36:02 +00:00
|
|
|
# TODO: implement `getReceipts` and reactivate this code
|
|
|
|
# await response.send(peer.network.chain.getReceipts(hashes))
|
2019-02-05 15:40:29 +00:00
|
|
|
|
2021-12-20 12:14:50 +00:00
|
|
|
proc receipts(peer: Peer, receipts: openArray[Receipt])
|
2019-02-05 15:40:29 +00:00
|
|
|
|