Commit 9278f945 authored by Sebastian Stammler's avatar Sebastian Stammler Committed by GitHub

op-service/sources: Always validate number of receipts when fetching receipts (#8834)

Even if we're trusting the rpc source. This is a cheap sanity check.
parent 3176c290
...@@ -327,6 +327,8 @@ func (s *EthClient) FetchReceipts(ctx context.Context, blockHash common.Hash) (e ...@@ -327,6 +327,8 @@ func (s *EthClient) FetchReceipts(ctx context.Context, blockHash common.Hash) (e
if err := validateReceipts(block, info.ReceiptHash(), txHashes, receipts); err != nil { if err := validateReceipts(block, info.ReceiptHash(), txHashes, receipts); err != nil {
return info, nil, fmt.Errorf("invalid receipts: %w", err) return info, nil, fmt.Errorf("invalid receipts: %w", err)
} }
} else if len(txHashes) != len(receipts) {
return info, nil, fmt.Errorf("unexpected number of receipts, expected: %d, got: %d", len(txHashes), len(receipts))
} }
return info, receipts, nil return info, receipts, nil
......
...@@ -180,7 +180,54 @@ func TestEthClient_WrongInfoByHash(t *testing.T) { ...@@ -180,7 +180,54 @@ func TestEthClient_WrongInfoByHash(t *testing.T) {
m.Mock.AssertExpectations(t) m.Mock.AssertExpectations(t)
} }
type validateReceiptsTest struct {
desc string
trustRPC bool
mutReceipts func(types.Receipts) types.Receipts
expError string
}
func TestEthClient_validateReceipts(t *testing.T) { func TestEthClient_validateReceipts(t *testing.T) {
mutBloom := func(rs types.Receipts) types.Receipts {
rs[2].Bloom[0] = 1
return rs
}
for _, tt := range []validateReceiptsTest{
{
desc: "no-trust-valid",
},
{
desc: "no-trust-invalid-mut-bloom",
mutReceipts: mutBloom,
expError: "invalid receipts",
},
{
desc: "trust-valid",
trustRPC: true,
},
{
desc: "trust-invalid-mut-bloom",
trustRPC: true,
mutReceipts: mutBloom, // should still pass if trusting rpc
},
{
desc: "trust-invalid-truncated",
trustRPC: true,
mutReceipts: func(rs types.Receipts) types.Receipts {
// remove last receipt should invalidate even if trusting RPC
return rs[:len(rs)-1]
},
expError: "unexpected number of receipts",
},
} {
t.Run(tt.desc, func(t *testing.T) {
testEthClient_validateReceipts(t, tt)
})
}
}
func testEthClient_validateReceipts(t *testing.T, test validateReceiptsTest) {
require := require.New(t) require := require.New(t)
mrpc := new(mockRPC) mrpc := new(mockRPC)
mrp := new(mockReceiptsProvider) mrp := new(mockReceiptsProvider)
...@@ -189,8 +236,9 @@ func TestEthClient_validateReceipts(t *testing.T) { ...@@ -189,8 +236,9 @@ func TestEthClient_validateReceipts(t *testing.T) {
txHashes := receiptTxHashes(receipts) txHashes := receiptTxHashes(receipts)
ctx := context.Background() ctx := context.Background()
// mutate a field to make validation fail. if mut := test.mutReceipts; mut != nil {
receipts[2].Bloom[0] = 1 receipts = mut(receipts)
}
mrpc.On("CallContext", ctx, mock.AnythingOfType("**sources.rpcBlock"), mrpc.On("CallContext", ctx, mock.AnythingOfType("**sources.rpcBlock"),
"eth_getBlockByHash", []any{block.Hash, true}). "eth_getBlockByHash", []any{block.Hash, true}).
...@@ -205,10 +253,18 @@ func TestEthClient_validateReceipts(t *testing.T) { ...@@ -205,10 +253,18 @@ func TestEthClient_validateReceipts(t *testing.T) {
ethcl := newEthClientWithCaches(nil, numTxs) ethcl := newEthClientWithCaches(nil, numTxs)
ethcl.client = mrpc ethcl.client = mrpc
ethcl.recProvider = mrp ethcl.recProvider = mrp
ethcl.trustRPC = false ethcl.trustRPC = test.trustRPC
_, _, err := ethcl.FetchReceipts(ctx, block.Hash) info, recs, err := ethcl.FetchReceipts(ctx, block.Hash)
require.ErrorContains(err, "invalid receipts") if test.expError != "" {
require.ErrorContains(err, test.expError)
} else {
require.NoError(err)
expInfo, _, err := block.Info(true, false)
require.NoError(err)
require.Equal(expInfo, info)
require.Equal(types.Receipts(receipts), recs)
}
mrpc.AssertExpectations(t) mrpc.AssertExpectations(t)
mrp.AssertExpectations(t) mrp.AssertExpectations(t)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment