Skip to content

eth: implement EIP-7975 (eth/70 - partial block receipt lists)#33153

Merged
fjl merged 54 commits intoethereum:masterfrom
healthykim:bs/eip7975-peer
Mar 30, 2026
Merged

eth: implement EIP-7975 (eth/70 - partial block receipt lists)#33153
fjl merged 54 commits intoethereum:masterfrom
healthykim:bs/eip7975-peer

Conversation

@healthykim
Copy link
Copy Markdown
Contributor

@healthykim healthykim commented Nov 11, 2025

This is a draft PR to add support for EIP-7975.
Overall changes

  • Each response is buffered in the peer’s receipt buffer when the lastBlockIncomplete field is true.
  • Continued request uses the same request id of its original request(RequestPartialReceipts).
  • Partial responses are verified in validateLastBlockReceipt.
  • Even if all receipts for partial blocks of the request are collected, those partial results are not sinked to the downloader, to avoid complexity. This assumes that partial response and buffering occur only in exceptional cases. (The complexity added to the queue can be checked in 1f32d8959)

@healthykim healthykim changed the title WIP: add eip-7975 EIP-7975: eth/70 - partial block receipt lists Nov 15, 2025
@healthykim healthykim changed the title EIP-7975: eth/70 - partial block receipt lists eth: implement EIP-7975 (eth/70 - partial block receipt lists) Nov 15, 2025
@healthykim healthykim marked this pull request as ready for review November 18, 2025 13:37
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/handlers.go Outdated
Comment thread eth/protocols/eth/handlers.go Outdated
Comment thread eth/protocols/eth/dispatcher.go Outdated
Comment thread eth/protocols/eth/peer.go
Comment thread eth/protocols/eth/peer.go
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread rlp/raw.go
Comment thread eth/protocols/eth/peer.go Outdated

// RequestReceipts fetches a batch of transaction receipts from a remote node.
func (p *Peer) RequestReceipts(hashes []common.Hash, sink chan *Response) (*Request, error) {
func (p *Peer) RequestReceipts(hashes []common.Hash, gasUsed []uint64, sink chan *Response) (*Request, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a short comment that explains gasUsed in the function godoc comment.

Comment thread eth/protocols/eth/handlers.go Outdated
Comment thread eth/protocols/eth/handlers.go
Comment thread eth/protocols/eth/peer.go Outdated
Comment thread eth/protocols/eth/peer.go Outdated
}

// Verify that the total number of transactions delivered is under the limit.
if uint64(previousTxs+lastReceipts.items.Len()) > gasUsed/21_000 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EIP-2780 changes the intrinsic cost of transactions to 4500gas. To apply this, we have to find a way to relay the block timestamp of the block to which this receipt list is related. Then we can perform a fork parameter lookup to find the correct cost. It's annoying but we need this check.

Comment thread eth/protocols/eth/peer.go Outdated
Comment on lines +533 to +548
content, _, err := rlp.SplitList(it.Value())
if err != nil {
return 0, fmt.Errorf("invalid receipt structure: %v", err)
}
rest := content
for range 3 {
_, _, rest, err = rlp.Split(rest)
if err != nil {
return 0, fmt.Errorf("invalid receipt structure: %v", err)
}
}
logsContent, _, err := rlp.SplitList(rest)
if err != nil {
return 0, fmt.Errorf("invalid receipt logs: %v", err)
}
log += uint64(len(logsContent))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code should live in a function in receipt.go. It is basically traversing the receipt object to find the logs data that should count towards the gas limit check.

Comment thread eth/protocols/eth/peer_test.go Outdated
Comment on lines +428 to +431
tresp = tracker.Response{ID: delivery.RequestId, MsgCode: ReceiptsMsg, Size: delivery.List.Len()}
if err = peer.tracker.Fulfil(tresp); err != nil {
t.Fatalf("tracker.Fulfil failed: %v", err)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think invoking the tracker here does not have a purpose in the test. If you want to test the handler behavior as it is done by handler, you basically have to invoke the handler function directly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we reuse IDs the tracker would raise an ID collision error if a request with the same ID was not fulfilled.

However, I agree that the test itself is not well structured, and its is also strange to be in peer_test.go. Since wwe already have devp2p tests and TestGetBlockPartialReceipt, I think it is okay to remove these tests.

@rjl493456442 rjl493456442 modified the milestones: 1.17.2, 1.17.3 Mar 30, 2026
@fjl fjl changed the title eth, cmd, rlp: implement EIP-7975 (eth/70 - partial block receipt lists) eth: implement EIP-7975 (eth/70 - partial block receipt lists) Mar 30, 2026
@fjl fjl merged commit 965bd6b into ethereum:master Mar 30, 2026
5 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants