mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 12:46:44 +00:00
eth/catalyst: wire up rest-api and update to new spec
This commit is contained in:
parent
8685b80f23
commit
85445ac3b6
4 changed files with 166 additions and 32 deletions
|
|
@ -31,13 +31,18 @@ const (
|
||||||
BytesPerFieldElement = 32 // EIP-4844
|
BytesPerFieldElement = 32 // EIP-4844
|
||||||
BytesPerBlob = FieldElementsPerBlob * BytesPerFieldElement
|
BytesPerBlob = FieldElementsPerBlob * BytesPerFieldElement
|
||||||
CellsPerExtBlob = 128 // EIP-7594
|
CellsPerExtBlob = 128 // EIP-7594
|
||||||
BytesPerCell = BytesPerBlob / CellsPerExtBlob
|
FieldElementsPerCell = 64 // EIP-7594
|
||||||
|
// A cell spans FIELD_ELEMENTS_PER_CELL field elements of the *extended*
|
||||||
|
// blob, so BytesPerCell = 64 * 32 = 2048. (Not BytesPerBlob/CellsPerExtBlob,
|
||||||
|
// which divides the original-blob byte count over the extended-blob cell
|
||||||
|
// count and halves the true size — see execution-apis refactor-ssz.md.)
|
||||||
|
BytesPerCell = FieldElementsPerCell * BytesPerFieldElement
|
||||||
MaxBalBytes = MaxBytesPerTx // EIP-7928 placeholder
|
MaxBalBytes = MaxBytesPerTx // EIP-7928 placeholder
|
||||||
MaxExecutionRequestsPerPayload = 1 << 8 // 256, EIP-7685
|
MaxExecutionRequestsPerPayload = 1 << 8 // 256, EIP-7685
|
||||||
MaxBytesPerExecutionRequest = MaxBytesPerTx // placeholder
|
MaxBytesPerExecutionRequest = MaxBytesPerTx // placeholder
|
||||||
MaxVersionedHashesPerRequest = 128 // Osaka
|
MaxVersionedHashesPerRequest = 128 // Osaka
|
||||||
MaxBlobsRequest = MaxVersionedHashesPerRequest
|
MaxBlobsRequest = MaxVersionedHashesPerRequest
|
||||||
MaxBodiesRequest = 128 // see spec open question; capabilities example uses 128
|
MaxBodiesRequest = 1 << 5 // 32, Shanghai
|
||||||
MaxErrorBytes = 1024
|
MaxErrorBytes = 1024
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
125
eth/catalyst/rest_backend.go
Normal file
125
eth/catalyst/rest_backend.go
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
// Copyright 2026 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package catalyst
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/engineapi"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/version"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// restBackend adapts the JSON-RPC ConsensusAPI to the engineapi.Backend
|
||||||
|
// contract that drives the REST + SSZ Engine API (execution-apis #793). Both
|
||||||
|
// surfaces share the same underlying logic; this adapter only translates
|
||||||
|
// shapes, it holds no state of its own.
|
||||||
|
type restBackend struct {
|
||||||
|
api *ConsensusAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
// newRESTBackend wraps a ConsensusAPI as an engineapi.Backend.
|
||||||
|
func newRESTBackend(api *ConsensusAPI) engineapi.Backend {
|
||||||
|
return &restBackend{api: api}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *restBackend) ForkchoiceUpdated(ctx context.Context, state engine.ForkchoiceStateV1, attrs *engine.PayloadAttributes, version engine.PayloadVersion) (engine.ForkChoiceResponse, error) {
|
||||||
|
return b.api.forkchoiceUpdated(ctx, state, attrs, version, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *restBackend) NewPayload(ctx context.Context, data engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte) (engine.PayloadStatusV1, error) {
|
||||||
|
return b.api.newPayload(ctx, data, versionedHashes, beaconRoot, requests, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *restBackend) GetPayload(id engine.PayloadID, allowedForks []forks.Fork) (*engine.ExecutionPayloadEnvelope, error) {
|
||||||
|
// full=true so the envelope carries the complete payload; versions=nil
|
||||||
|
// because the REST router selects the fork from the URL, not the payload
|
||||||
|
// id's embedded version. allowedForks enforces the URL fork's era.
|
||||||
|
return b.api.getPayload(id, true, nil, allowedForks)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *restBackend) GetBlobs(hashes []common.Hash, cellProofs bool) ([]*engine.BlobAndProofV2, []*engine.BlobAndProofV1, error) {
|
||||||
|
if cellProofs {
|
||||||
|
v2, err := b.api.getBlobs(hashes, true)
|
||||||
|
return v2, nil, err
|
||||||
|
}
|
||||||
|
v1, err := b.api.GetBlobsV1(hashes)
|
||||||
|
return nil, v1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *restBackend) BodiesByHash(hashes []common.Hash) ([]*types.Body, []uint64) {
|
||||||
|
chain := b.api.eth.BlockChain()
|
||||||
|
bodies := make([]*types.Body, len(hashes))
|
||||||
|
timestamps := make([]uint64, len(hashes))
|
||||||
|
for i, h := range hashes {
|
||||||
|
block := chain.GetBlockByHash(h)
|
||||||
|
if block == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bodies[i] = block.Body()
|
||||||
|
timestamps[i] = block.Time()
|
||||||
|
}
|
||||||
|
return bodies, timestamps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *restBackend) BodiesByRange(from, count uint64) ([]*types.Body, []uint64) {
|
||||||
|
chain := b.api.eth.BlockChain()
|
||||||
|
// Truncate at head: blocks past the latest known block are omitted, never
|
||||||
|
// padded with nil (the spec's "no trailing nulls" rule for range queries).
|
||||||
|
head := chain.CurrentBlock().Number.Uint64()
|
||||||
|
if from > head {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
last := min(from+count-1, head)
|
||||||
|
n := last - from + 1
|
||||||
|
bodies := make([]*types.Body, 0, n)
|
||||||
|
timestamps := make([]uint64, 0, n)
|
||||||
|
for num := from; num <= last; num++ {
|
||||||
|
block := chain.GetBlockByNumber(num)
|
||||||
|
if block == nil {
|
||||||
|
// In-range but pruned: keep the slot so the entry reports
|
||||||
|
// available=false; only past-head blocks are dropped (above).
|
||||||
|
bodies = append(bodies, nil)
|
||||||
|
timestamps = append(timestamps, 0)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bodies = append(bodies, block.Body())
|
||||||
|
timestamps = append(timestamps, block.Time())
|
||||||
|
}
|
||||||
|
return bodies, timestamps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *restBackend) ForkFromTimestamp(ts uint64) forks.Fork {
|
||||||
|
return b.api.config().LatestFork(ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *restBackend) ClientVersion() engine.ClientVersionV1 {
|
||||||
|
commit := make([]byte, 4)
|
||||||
|
if vcs, ok := version.VCS(); ok {
|
||||||
|
commit = common.FromHex(vcs.Commit)[0:4]
|
||||||
|
}
|
||||||
|
return engine.ClientVersionV1{
|
||||||
|
Code: engine.ClientCode,
|
||||||
|
Name: engine.ClientName,
|
||||||
|
Version: version.WithMeta,
|
||||||
|
Commit: hexutil.Encode(commit),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -56,8 +56,12 @@ type Backend interface {
|
||||||
// router can enforce the URL fork's era window.
|
// router can enforce the URL fork's era window.
|
||||||
BodiesByHash(hashes []common.Hash) ([]*types.Body, []uint64)
|
BodiesByHash(hashes []common.Hash) ([]*types.Body, []uint64)
|
||||||
|
|
||||||
// BodiesByRange returns block bodies for [from, from+count). Same shape
|
// BodiesByRange returns block bodies for [from, from+count), but the
|
||||||
// as BodiesByHash.
|
// result MUST be truncated at the latest known block: blocks past head are
|
||||||
|
// omitted, not padded with nil. The spec's "no trailing nulls" rule means a
|
||||||
|
// range response has length min(count, head-from+1) for from <= head, and
|
||||||
|
// is empty for from > head. In-range-but-pruned blocks are still returned as
|
||||||
|
// nil entries (-> available=false); only past-head blocks are dropped.
|
||||||
BodiesByRange(from, count uint64) ([]*types.Body, []uint64)
|
BodiesByRange(from, count uint64) ([]*types.Body, []uint64)
|
||||||
|
|
||||||
// ForkFromTimestamp returns the fork active at timestamp ts.
|
// ForkFromTimestamp returns the fork active at timestamp ts.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue