diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 874b4ad5a5..117e1b0aba 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -742,7 +742,7 @@ func testGetBlockAccessLists(t *testing.T, protocol uint) { var ( hashes []common.Hash - expect rlp.RawList[RawBlockAccessList] + expect rlp.RawList[rlp.RawValue] ) for i := uint64(0); i <= backend.chain.CurrentBlock().Number.Uint64(); i++ { block := backend.chain.GetBlockByNumber(i) @@ -771,6 +771,42 @@ func testGetBlockAccessLists(t *testing.T, protocol uint) { } } +// TestBlockAccessListsUnavailableDecode checks that a BlockAccessLists response +// containing the EIP-8159 unavailability marker (RLP empty string). +func TestBlockAccessListsUnavailableDecode(t *testing.T) { + t.Parallel() + + balRaw := makeTestBAL(t, common.Address{0x11}) + + // Assemble a response the way the serving side does, with the middle + // entry signaled as unavailable. + var list rlp.RawList[rlp.RawValue] + list.AppendRaw(balRaw) + list.AppendRaw(rlp.EmptyString) + list.AppendRaw(balRaw) + + enc, err := rlp.EncodeToBytes(&BlockAccessListPacket{RequestId: 42, List: list}) + if err != nil { + t.Fatalf("failed to encode packet: %v", err) + } + var packet BlockAccessListPacket + if err := rlp.DecodeBytes(enc, &packet); err != nil { + t.Fatalf("failed to decode packet: %v", err) + } + bals, err := packet.List.Items() + if err != nil { + t.Fatalf("failed to decode BAL entries: %v", err) + } + if len(bals) != 3 { + t.Fatalf("wrong entry count: got %d, want 3", len(bals)) + } + for i, want := range [][]byte{balRaw, rlp.EmptyString, balRaw} { + if !bytes.Equal(bals[i], want) { + t.Errorf("entry %d mismatch: got %x, want %x", i, bals[i], want) + } + } +} + type decoder struct { msg []byte } diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index 71942cc9ad..f8f5c8e8e7 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -679,10 +679,10 @@ func handleGetBlockAccessLists(backend Backend, msg Decoder, peer *Peer) error { // serviceGetBlockAccessListsQuery assembles the response to a BAL query. // Unavailable BALs are returned as empty list entries. -func serviceGetBlockAccessListsQuery(chain *core.BlockChain, query GetBlockAccessListsRequest) rlp.RawList[RawBlockAccessList] { +func serviceGetBlockAccessListsQuery(chain *core.BlockChain, query GetBlockAccessListsRequest) rlp.RawList[rlp.RawValue] { var ( bytes int - bals rlp.RawList[RawBlockAccessList] + bals rlp.RawList[rlp.RawValue] ) for _, hash := range query { if bytes >= softResponseLimit || bals.Len() >= maxBALsServe { @@ -720,7 +720,12 @@ func handleBlockAccessLists(backend Backend, msg Decoder, peer *Peer) error { metadata := func() interface{} { hashes := make([]common.Hash, len(bals)) for i := range bals { - hashes[i] = crypto.Keccak256Hash(bals[i].Bytes()) + // Unavailable BALs (signaled by the empty string) are marked + // with the zero hash + if bytes.Equal(bals[i], rlp.EmptyString) { + continue + } + hashes[i] = crypto.Keccak256Hash(bals[i]) } return hashes } diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index 63f93840c3..1e33fbe408 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -258,7 +258,7 @@ func (p *Peer) ReplyReceiptsRLP70(id uint64, receipts rlp.RawList[*ReceiptList], } // ReplyBlockAccessLists is the response to GetBlockAccessLists (EIP-8159). -func (p *Peer) ReplyBlockAccessLists(id uint64, list rlp.RawList[RawBlockAccessList]) error { +func (p *Peer) ReplyBlockAccessLists(id uint64, list rlp.RawList[rlp.RawValue]) error { return p2p.Send(p.rw, BlockAccessListsMsg, &BlockAccessListPacket{ RequestId: id, List: list, diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index a6c45f83ec..e7ffcf6d5e 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -24,7 +24,6 @@ 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/core/types/bal" "github.com/ethereum/go-ethereum/rlp" ) @@ -299,15 +298,14 @@ type GetBlockAccessListsPacket struct { GetBlockAccessListsRequest } -type RawBlockAccessList struct { - rlp.RawList[bal.AccountAccess] -} - -type BlockAccessListResponse []RawBlockAccessList +// BlockAccessListResponse holds one raw entry per requested hash. Entries are +// kept as raw values because, per EIP-8159, the RLP empty string signals an +// unavailable BAL (an empty list is itself a valid BAL). +type BlockAccessListResponse []rlp.RawValue type BlockAccessListPacket struct { RequestId uint64 - List rlp.RawList[RawBlockAccessList] + List rlp.RawList[rlp.RawValue] } func (*StatusPacket) Name() string { return "Status" }