Skip to content

eth/protocols/eth/protocol_pow.go — Version Comparison

v1.17.3 v1.17.4
Branch etc/v1.17.3-full-node etc/v1.17.4-full-node
Delta +123 -0 +196 -0

Diff between branches

diff --git a/eth/protocols/eth/protocol_pow.go b/eth/protocols/eth/protocol_pow.go
index 5597790d8..ac0e0d5c0 100644
--- a/eth/protocols/eth/protocol_pow.go
+++ b/eth/protocols/eth/protocol_pow.go
@@ -23,6 +23,7 @@ import (
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/forkid"
    "github.com/ethereum/go-ethereum/core/types"
+   "github.com/ethereum/go-ethereum/rlp"
 )

 const ETH68 = 68
@@ -88,15 +89,65 @@ func (p *NewBlockHashesPacket) Unpack() ([]common.Hash, []uint64) {
 func (*NewBlockHashesPacket) Name() string { return "NewBlockHashes" }
 func (*NewBlockHashesPacket) Kind() byte   { return NewBlockHashesMsg }

-// NewBlockPacket is the network packet for the block propagation message.
+// maxBlockAnnouncements bounds the hashes a single announcement message may
+// carry. Past maxKnownBlocks the message defeats itself: every hash is fed into
+// the peer's known-blocks cache, which evicts at that size, so the tail of an
+// oversized message pushes out its own head. It also sits well above the block
+// fetcher's hashLimit, the number of announcements from one peer it tracks at a
+// time, in the same arrangement upstream uses for transactions, where the
+// protocol-level maxTransactionAnnouncements sits above the fetcher-level
+// maxTxAnnounces. For scale, our own side sends one hash per message.
+const maxBlockAnnouncements = maxKnownBlocks
+
+// maxBlockTransactions bounds the number of transactions a propagated block may
+// carry before it is rejected without being decoded. A block cannot hold more
+// transactions than its gas limit admits at the 21000 gas floor of a plain
+// transfer, which puts ETC's current 8M limit at a few hundred; this is set far
+// above that so it keeps holding for any plausible future gas limit, and equals
+// the figure upstream uses for the analogous cap on transaction broadcasts
+// (maxTransactionAnnouncements). Computing it from the announced gas limit
+// instead would be self-defeating: on this message that field is attacker
+// controlled.
+const maxBlockTransactions = 5000
+
+// maxBlockUncles is the maximum number of uncles a block can contain, per the
+// ethash/etchash consensus rules. Blocks announcing more cannot be valid.
+const maxBlockUncles = 2
+
+// NewBlockPacket is the network packet for the block propagation message. It is
+// what the sending side encodes and what the backend consumes; inbound messages
+// are decoded into rawNewBlockPacket first and assembled into this afterwards.
 type NewBlockPacket struct {
    Block *types.Block
    TD    *big.Int
 }

+func (*NewBlockPacket) Name() string { return "NewBlock" }
+func (*NewBlockPacket) Kind() byte   { return NewBlockMsg }
+
+// rawNewBlockPacket is the receiving side's view of NewBlockMsg, holding the
+// block body encoded so that its item counts can be checked, and the body
+// verified against the header, before any of it is materialized. A broadcast
+// carries no request id, so there is nothing to match it against: the counts
+// are all that stands between the message size limit and the heap.
+type rawNewBlockPacket struct {
+   Block rawBlock
+   TD    *big.Int
+}
+
+// rawBlock mirrors the block encoding, [header, txs, uncles], keeping the two
+// lists encoded in the manner of BlockBody. Withdrawals are deliberately absent:
+// a PoW block carries none, so a message that includes them is rejected as
+// having too many elements.
+type rawBlock struct {
+   Header       *types.Header
+   Transactions rlp.RawList[*types.Transaction]
+   Uncles       rlp.RawList[*types.Header]
+}
+
 // sanityCheck verifies that the values are reasonable, as a DoS protection
-func (request *NewBlockPacket) sanityCheck() error {
-   if err := request.Block.SanityCheck(); err != nil {
+func (request *rawNewBlockPacket) sanityCheck() error {
+   if err := request.Block.Header.SanityCheck(); err != nil {
        return err
    }
    //TD at mainnet block #7753254 is 76 bits. If it becomes 100 million times
@@ -107,8 +158,30 @@ func (request *NewBlockPacket) sanityCheck() error {
    return nil
 }

-func (*NewBlockPacket) Name() string { return "NewBlock" }
-func (*NewBlockPacket) Kind() byte   { return NewBlockMsg }
+// body returns the encoded body parts in the shape the shared hashing helpers
+// consume.
+func (b *rawBlock) body() BlockBody {
+   return BlockBody{Transactions: b.Transactions, Uncles: b.Uncles}
+}
+
+// GetReceiptsPacket represents a block receipts query with request ID wrapping.
+type GetReceiptsPacket struct {
+   RequestId uint64
+   GetReceiptsRequest
+}
+
+// ReceiptsPacket68 is the network packet for block receipts distribution with
+// request ID wrapping.
+type ReceiptsPacket68 struct {
+   RequestId uint64
+   List      rlp.RawList[*ReceiptList68]
+}
+
+// ReceiptsRLPPacket is ReceiptsRLPResponse with request ID wrapping.
+type ReceiptsRLPPacket struct {
+   RequestId uint64
+   ReceiptsRLPResponse
+}

 // Unpack retrieves the transactions and uncles from each block body in the response.
 // This is needed for PoW block fetcher which processes bodies differently.
← Back to Version Comparison