Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/rpcdaemon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ The following table shows the current implementation status of Erigon's RPC daem
| engine_getPayloadBodiesByRangeV1 | Yes | |
| engine_getClientVersionV1 | Yes | |
| engine_getBlobsV1 | Yes | |
| engine_getBlobsV2 | Yes | Added in Fusaka |
| engine_getBlobsV3 | Yes | Added with BPO3 |
| | | |
| debug_getRawReceipts | Yes | `debug_` expected to be private |
| debug_accountRange | Yes | |
Expand Down
15 changes: 15 additions & 0 deletions execution/engineapi/engine_api_methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ var ourCapabilities = []string{
"engine_getClientVersionV1",
"engine_getBlobsV1",
"engine_getBlobsV2",
"engine_getBlobsV3",
}

// Returns the most recent version of the payload(for the payloadID) at the time of receiving the call
Expand Down Expand Up @@ -224,6 +225,20 @@ func (e *EngineServer) GetBlobsV1(ctx context.Context, blobHashes []common.Hash)

func (e *EngineServer) GetBlobsV2(ctx context.Context, blobHashes []common.Hash) ([]*engine_types.BlobAndProofV2, error) {
e.logger.Debug("[GetBlobsV2] Received Request", "hashes", len(blobHashes))
// GetBlobsV2 was actually introduced in Fusaka,
// but here we're using the Pectra version to differentiate it from GetBlobsV3.
resp, err := e.getBlobs(ctx, blobHashes, clparams.ElectraVersion)
if err != nil {
return nil, err
}
if ret, ok := resp.([]*engine_types.BlobAndProofV2); ok {
return ret, err
}
return nil, err
}

func (e *EngineServer) GetBlobsV3(ctx context.Context, blobHashes []common.Hash) ([]*engine_types.BlobAndProofV2, error) {
e.logger.Debug("[GetBlobsV3] Received Request", "hashes", len(blobHashes))
resp, err := e.getBlobs(ctx, blobHashes, clparams.FuluVersion)
if err != nil {
return nil, err
Expand Down
30 changes: 25 additions & 5 deletions execution/engineapi/engine_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1029,17 +1029,36 @@ func (e *EngineServer) getBlobs(ctx context.Context, blobHashes []common.Hash, v
return nil, nil
}

if version == clparams.FuluVersion {
switch version {
case clparams.FuluVersion: // GetBlobsV3
ret := make([]*engine_types.BlobAndProofV2, len(blobHashes))
for i, bwp := range res.BlobsWithProofs {
logHead := fmt.Sprintf("\n%x: ", blobHashes[i])
if len(bwp.Blob) == 0 {
// engine_getblobsv2 MUST return null in case of any missing or older version blobs
logLine = append(logLine, logHead, "nil")
} else if len(bwp.Proofs) != int(params.CellsPerExtBlob) {
logLine = append(logLine, logHead, fmt.Sprintf("pre-Fusaka proofs, len(proof)=%d", len(bwp.Proofs)))
} else {
ret[i] = &engine_types.BlobAndProofV2{Blob: bwp.Blob, CellProofs: make([]hexutil.Bytes, params.CellsPerExtBlob)}
for c := range params.CellsPerExtBlob {
ret[i].CellProofs[c] = bwp.Proofs[c]
}
logLine = append(logLine, logHead, fmt.Sprintf("OK, len(blob)=%d", len(bwp.Blob)))
}
}
e.logger.Debug("[GetBlobsV3]", "Responses", logLine)
return ret, nil
case clparams.ElectraVersion: // GetBlobsV2
ret := make([]*engine_types.BlobAndProofV2, len(blobHashes))
for i, bwp := range res.BlobsWithProofs {
logHead := fmt.Sprintf("\n%x: ", blobHashes[i])
if len(bwp.Blob) == 0 {
// engine_getBlobsV2 MUST return null in case of any missing or older version blobs
ret = nil
logLine = append(logLine, logHead, "nil")
break
} else if len(bwp.Proofs) != int(params.CellsPerExtBlob) {
// engine_getblobsv2 MUST return null in case of any missing or older version blobs
// engine_getBlobsV2 MUST return null in case of any missing or older version blobs
ret = nil
logLine = append(logLine, logHead, fmt.Sprintf("pre-Fusaka proofs, len(proof)=%d", len(bwp.Proofs)))
break
Expand All @@ -1053,7 +1072,7 @@ func (e *EngineServer) getBlobs(ctx context.Context, blobHashes []common.Hash, v
}
e.logger.Debug("[GetBlobsV2]", "Responses", logLine)
return ret, nil
} else if version == clparams.DenebVersion {
case clparams.DenebVersion: // GetBlobsV1
ret := make([]*engine_types.BlobAndProofV1, len(blobHashes))
for i, bwp := range res.BlobsWithProofs {
logHead := fmt.Sprintf("\n%x: ", blobHashes[i])
Expand All @@ -1068,8 +1087,9 @@ func (e *EngineServer) getBlobs(ctx context.Context, blobHashes []common.Hash, v
}
e.logger.Debug("[GetBlobsV1]", "Responses", logLine)
return ret, nil
default:
return nil, nil
}
return nil, nil
}

func waitForResponse(maxWait time.Duration, waitCondnF func() (bool, error)) (bool, error) {
Expand Down
63 changes: 63 additions & 0 deletions execution/engineapi/engine_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,69 @@ func TestGetBlobsV2(t *testing.T) {
blobHashes = blobHashes[1:]
blobsResp, err = engineServer.GetBlobsV2(ctx, blobHashes)
require.NoError(err)
require.Len(blobsResp, 2)
require.Equal(blobsResp[0].Blob, hexutil.Bytes(wrappedTxn.Blobs[0][:]))
require.Equal(blobsResp[1].Blob, hexutil.Bytes(wrappedTxn.Blobs[1][:]))

for i := range 128 {
require.Equal(blobsResp[0].CellProofs[i], hexutil.Bytes(wrappedTxn.Proofs[i][:]))
require.Equal(blobsResp[1].CellProofs[i], hexutil.Bytes(wrappedTxn.Proofs[i+128][:]))
}
}

func TestGetBlobsV3(t *testing.T) {
logger := log.New()
buf := bytes.NewBuffer(nil)
mockSentry, require := mock.MockWithTxPoolOsaka(t), require.New(t)
oneBlockStep(mockSentry, require, t)

wrappedTxn := types.MakeV1WrappedBlobTxn(uint256.MustFromBig(mockSentry.ChainConfig.ChainID))
txn, err := types.SignTx(wrappedTxn, *types.LatestSignerForChainID(mockSentry.ChainConfig.ChainID), mockSentry.Key)
require.NoError(err)
dt := &wrappedTxn.Tx.DynamicFeeTransaction
v, r, s := txn.RawSignatureValues()
dt.V.Set(v)
dt.R.Set(r)
dt.S.Set(s)

ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, mockSentry)
txPool := direct.NewTxPoolClient(mockSentry.TxPoolGrpcServer)

ff := rpchelper.New(ctx, rpchelper.DefaultFiltersConfig, nil, txPool, txpoolproto.NewMiningClient(conn), func() {}, mockSentry.Log)
api := jsonrpc.NewEthAPI(newBaseApiForTest(mockSentry), mockSentry.DB, nil, txPool, nil, 5000000, ethconfig.Defaults.RPCTxFeeCap, 100_000, false, 100_000, 128, logger)

executionRpc := direct.NewExecutionClientDirect(mockSentry.Eth1ExecutionService)
eth := rpcservices.NewRemoteBackend(nil, mockSentry.DB, mockSentry.BlockReader)
engineServer := NewEngineServer(mockSentry.Log, mockSentry.ChainConfig, executionRpc, nil, false, false, true, txPool, DefaultFcuTimeout)
ctx, cancel := context.WithCancel(ctx)
var eg errgroup.Group
t.Cleanup(func() {
err := eg.Wait() // wait for clean exit
require.ErrorIs(err, context.Canceled)
})
t.Cleanup(cancel)
eg.Go(func() error {
return engineServer.Start(ctx, &httpcfg.HttpCfg{}, mockSentry.DB, mockSentry.BlockReader, ff, nil, mockSentry.Engine, eth, nil)
})

err = wrappedTxn.MarshalBinaryWrapped(buf)
require.NoError(err)
hh, err := api.SendRawTransaction(ctx, buf.Bytes())
require.NoError(err)
require.NotEmpty(hh)

blobHashes := append([]common.Hash{{}}, wrappedTxn.Tx.BlobVersionedHashes...)
blobsResp, err := engineServer.GetBlobsV3(ctx, blobHashes)
require.NoError(err)
require.Len(blobsResp, 3) // Unlike GetBlobsV2, only the missing blob should be nil
require.Nil(blobsResp[0])
require.Equal(blobsResp[1].Blob, hexutil.Bytes(wrappedTxn.Blobs[0][:]))
require.Equal(blobsResp[2].Blob, hexutil.Bytes(wrappedTxn.Blobs[1][:]))

blobHashes = blobHashes[1:]
blobsResp, err = engineServer.GetBlobsV3(ctx, blobHashes)
require.NoError(err)
require.Len(blobsResp, 2)
require.Equal(blobsResp[0].Blob, hexutil.Bytes(wrappedTxn.Blobs[0][:]))
require.Equal(blobsResp[1].Blob, hexutil.Bytes(wrappedTxn.Blobs[1][:]))

Expand Down
2 changes: 1 addition & 1 deletion execution/engineapi/engine_types/jsonrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ type BlobAndProofV1 struct {
Proof hexutil.Bytes `json:"proof" gencodec:"required"`
}

// BlobAndProofV2 holds one item for engine_getBlobsV2
// BlobAndProofV2 holds one item for engine_getBlobsV2/engine_getBlobsV3
type BlobAndProofV2 struct {
Blob hexutil.Bytes `json:"blob" gencodec:"required"`
CellProofs []hexutil.Bytes `json:"proofs" gencodec:"required"`
Expand Down
2 changes: 2 additions & 0 deletions execution/engineapi/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ type EngineAPI interface {
GetPayloadBodiesByRangeV1(ctx context.Context, start, count hexutil.Uint64) ([]*engine_types.ExecutionPayloadBody, error)
GetClientVersionV1(ctx context.Context, callerVersion *engine_types.ClientVersionV1) ([]engine_types.ClientVersionV1, error)
GetBlobsV1(ctx context.Context, blobHashes []common.Hash) ([]*engine_types.BlobAndProofV1, error)
GetBlobsV2(ctx context.Context, blobHashes []common.Hash) ([]*engine_types.BlobAndProofV2, error)
GetBlobsV3(ctx context.Context, blobHashes []common.Hash) ([]*engine_types.BlobAndProofV2, error)
}
2 changes: 1 addition & 1 deletion txnprovider/txpool/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1551,7 +1551,7 @@ func TestWrappedSixBlobTxnExceedsRlpLimit(t *testing.T) {
require.NoError(err)
}

func TestGetBlobsV1(t *testing.T) {
func TestGetBlobs(t *testing.T) {
assert, require := assert.New(t), require.New(t)
ch := make(chan Announcements, 5)
coreDB := temporaltest.NewTestDB(t, datadir.New(t.TempDir()))
Expand Down
Loading