Skip to content

Commit

Permalink
Synchronizer support Feijoa Part 1 (#3560)
Browse files Browse the repository at this point in the history
* update go library to v1.13.14
* Etherman: Add a consensus client for the retrieve the Blobs (./beacon_client)
* Etherman: Add etherman new structure for Feija events (to be able to adapt zkevm-l1-sync library)
* Etherman: Add support for EIP-4844 (using beacon client)
* Etherman: process sequenceBlob for CallData, synchronizer support the event (missing Blob support)
* Etherman:  if Consensus clients fails disable Feijoa support (this have to be converted in a error)
* State: Add BlobSequences (It's probably not the final version)
* Synchronizer: Add initial support to synchronizer to SequenceBlobs (write sequence) (missing process BlobInner)
---------

Co-authored-by: tclemos <thiago@polygon.technology>
  • Loading branch information
joanestebanr and tclemos authored Apr 18, 2024
1 parent d565619 commit bdf9f34
Show file tree
Hide file tree
Showing 48 changed files with 84,791 additions and 105 deletions.
80,082 changes: 80,082 additions & 0 deletions beacon_client/beacon-node-oapi.json

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions beacon_client/beacon_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//go:generate oapi-codegen -package=examplepkg -generate=types,client,spec -o=examplepkg/example-client.go beacon-node-oapi.json
package beaconclient

import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)

// BeaconAPIClient client of Beacon API
// https://ethereum.github.io/beacon-APIs/
type BeaconAPIClient struct {
urlBase string
}

// NewBeaconAPIClient creates an instance of client
func NewBeaconAPIClient(url string) *BeaconAPIClient {
return &BeaconAPIClient{
urlBase: url,
}
}

// BeaconAPIResponse represents the response of the beacon API
type BeaconAPIResponse struct {
Result json.RawMessage
}

// JSONRPCBeaconCall executes restapi call to beacon-api node
func JSONRPCBeaconCall(ctx context.Context, urlBase, methodPath string) (BeaconAPIResponse, error) {
//url := path.Join(urlBase, methodPath)
url := fmt.Sprintf("%s%s", urlBase, methodPath)
httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody)
if err != nil {
return BeaconAPIResponse{}, err
}
httpReq.Header.Add("Content-type", "application/json")

httpRes, err := http.DefaultClient.Do(httpReq)
if err != nil {
return BeaconAPIResponse{}, err
}

resBody, err := io.ReadAll(httpRes.Body)
if err != nil {
return BeaconAPIResponse{}, err
}
defer httpRes.Body.Close()

if httpRes.StatusCode != http.StatusOK {
return BeaconAPIResponse{}, fmt.Errorf("BeaconClient fails url:%s status_code:%v response:%v", url, httpRes.StatusCode, string(resBody))
}

return BeaconAPIResponse{
Result: resBody,
}, nil
}

func unserializeGenericResponse[T any](response BeaconAPIResponse) (T, error) {
var result T
err := json.Unmarshal(response.Result, &result)
if err != nil {
var zero T
return zero, err
}
return result, nil
}
92 changes: 92 additions & 0 deletions beacon_client/req_beacon_blob_sidecars.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package beaconclient

import (
"context"
"fmt"
"strconv"

"github.com/0xPolygonHermez/zkevm-node/hex"
)

const beaconBlobSidecarsPath = "/eth/v1/beacon/blob_sidecars/"

// BeaconBlobSidecarsResponse represents the response of the beacon blob sidecars endpoint
type BeaconBlobSidecarsResponse struct {
Sidecars map[uint64]BeaconBlobSidecarResponse
}

// BeaconBlobSidecarResponse represents the response of the config spec endpoint
type BeaconBlobSidecarResponse struct {
Index uint64
KzgCommitment string
Blob []byte
}

type beaconBlobSidecarsResponseInternal struct {
Data []struct {
Index string `json:"index"`
Blob string `json:"blob"`
KzgCommitment string `json:"kzg_commitment"`
KzgProof string `json:"kzg_proof"`
SignedBlockHeader struct {
Message struct {
Slot string `json:"slot"`
ProposerIndex string `json:"proposer_index"`
ParentRoot string `json:"parent_root"`
StateRoot string `json:"state_root"`
BodyRoot string `json:"body_root"`
} `json:"message"`
Signature string `json:"signature"`
} `json:"signed_block_header"`
KzgCommitmentInclusionProof []string `json:"kzg_commitment_inclusion_proof"`
} `json:"data"`
}

func has0xPrefix(str string) bool {
return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')
}

func convertBeaconBlobSidecarsResponseInternal(data beaconBlobSidecarsResponseInternal) (*BeaconBlobSidecarsResponse, error) {
response := BeaconBlobSidecarsResponse{
Sidecars: make(map[uint64]BeaconBlobSidecarResponse),
}
for _, sidecar := range data.Data {
index, err := strconv.ParseUint(sidecar.Index, 0, hex.BitSize64)
if err != nil {
return nil, fmt.Errorf("error parsing Index: %v", err)
}
//common.Hex2Bytes(sidecar.Blob)
if has0xPrefix(sidecar.Blob) {
sidecar.Blob = sidecar.Blob[2:]
}
blob, err := hex.DecodeHex(sidecar.Blob)
if err != nil {
return nil, fmt.Errorf("error decoding Blob: %v", err)
}
response.Sidecars[index] = BeaconBlobSidecarResponse{
Index: index,
KzgCommitment: sidecar.KzgCommitment,
Blob: blob,
}
}
return &response, nil
}

// BeaconBlobSidecars fetches the blob sidecars for a given blockID
func (c *BeaconAPIClient) BeaconBlobSidecars(ctx context.Context, blockID uint64) (*BeaconBlobSidecarsResponse, error) {
response, err := JSONRPCBeaconCall(ctx, c.urlBase, beaconBlobSidecarsPath+fmt.Sprintf("%d", blockID))
if err != nil {
return nil, err
}

internalStruct, err := unserializeGenericResponse[beaconBlobSidecarsResponseInternal](response)
if err != nil {
return nil, err
}

responseData, err := convertBeaconBlobSidecarsResponseInternal(internalStruct)
if err != nil {
return nil, err
}
return responseData, nil
}
60 changes: 60 additions & 0 deletions beacon_client/req_beacon_genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package beaconclient

import (
"context"
"fmt"
"strconv"

"github.com/0xPolygonHermez/zkevm-node/hex"
"github.com/ethereum/go-ethereum/common"
)

// /eth/v1/beacon/genesis
const beaconGenesisPath = "/eth/v1/beacon/genesis"

// BeaconGenesisResponse represents the response of the beacon genesis endpoint
type BeaconGenesisResponse struct {
GenesisTime uint64
GenesisValidatorsRoot common.Address
GenesisForkVersion string
}

type beaconGenesisResponseInternal struct {
Data struct {
GenesisTime string `json:"genesis_time"`
GenesisValidatorsRoot string `json:"genesis_validators_root"`
GenesisForkVersion string `json:"genesis_fork_version"`
} `json:"data"`
}

func convertBeaconGenesisResponseInternal(data beaconGenesisResponseInternal) (BeaconGenesisResponse, error) {
genesisTime, err := strconv.ParseUint(data.Data.GenesisTime, 0, hex.BitSize64)
if err != nil {
return BeaconGenesisResponse{}, fmt.Errorf("error parsing genesisTime: %v", err)
}
res := BeaconGenesisResponse{
GenesisTime: genesisTime,
GenesisValidatorsRoot: common.HexToAddress(data.Data.GenesisValidatorsRoot),
GenesisForkVersion: data.Data.GenesisForkVersion,
}
return res, nil
}

// BeaconGenesis request the current beacon chain genesis
func (c *BeaconAPIClient) BeaconGenesis(ctx context.Context) (*BeaconGenesisResponse, error) {
response, err := JSONRPCBeaconCall(ctx, c.urlBase, beaconGenesisPath)
if err != nil {
return nil, err
}

internalStruct, err := unserializeGenericResponse[beaconGenesisResponseInternal](response)
if err != nil {
return nil, err
}

responseData, err := convertBeaconGenesisResponseInternal(internalStruct)
if err != nil {
return nil, err
}
return &responseData, nil
}
64 changes: 64 additions & 0 deletions beacon_client/req_config_spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package beaconclient

import (
"context"
"fmt"
"strconv"

"github.com/0xPolygonHermez/zkevm-node/hex"
)

// ConfigSpec returns the current beacon chain configuration
// Curl example:
// curl -X 'GET' \
// 'http://localhost/eth/v1/config/spec' \
// -H 'accept: application/json'
const configSpecPath = "/eth/v1/config/spec"

// ConfigSpecNodeResponse represents the response of the config spec endpoint
type ConfigSpecNodeResponse struct {
SecondsPerSlot uint64
SecondsPerEth1Block uint64
}

type configSpecNodeResponseInternal struct {
Data struct {
SecondsPerSlot string `json:"SECONDS_PER_SLOT"`
SecondsPerEth1Block string `json:"SECONDS_PER_ETH1_BLOCK"`
}
}

func convertConfigSpecResponseInternal(data configSpecNodeResponseInternal) (ConfigSpecNodeResponse, error) {
tmpSecondsPerSlot, err := strconv.ParseUint(data.Data.SecondsPerSlot, 0, hex.BitSize64)
if err != nil {
return ConfigSpecNodeResponse{}, fmt.Errorf("error parsing SecondsPerSlot: %v", err)
}
tmpSecondsPerEth1Block, err := strconv.ParseUint(data.Data.SecondsPerEth1Block, 0, hex.BitSize64)
if err != nil {
return ConfigSpecNodeResponse{}, fmt.Errorf("error parsing SecondsPerSlot: %v", err)
}
res := ConfigSpecNodeResponse{
SecondsPerSlot: tmpSecondsPerSlot,
SecondsPerEth1Block: tmpSecondsPerEth1Block,
}
return res, nil
}

// ConfigSpec returns the current beacon chain configuration
func (c *BeaconAPIClient) ConfigSpec(ctx context.Context) (*ConfigSpecNodeResponse, error) {
response, err := JSONRPCBeaconCall(ctx, c.urlBase, configSpecPath)
if err != nil {
return nil, err
}

internalStruct, err := unserializeGenericResponse[configSpecNodeResponseInternal](response)
if err != nil {
return nil, err
}

responseData, err := convertConfigSpecResponseInternal(internalStruct)
if err != nil {
return nil, err
}
return &responseData, nil
}
18 changes: 18 additions & 0 deletions db/migrations/state/0021.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-- +migrate Up


-- Add first blob_sequence?
CREATE TABLE state.blob_sequence
(
index BIGINT PRIMARY KEY,
coinbase VARCHAR,
final_acc_input_hash VARCHAR,
first_blob_sequenced BIGINT,
last_blob_sequenced BIGINT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
block_num BIGINT NOT NULL REFERENCES state.block (block_num) ON DELETE CASCADE
);



-- +migrate Down
Loading

0 comments on commit bdf9f34

Please sign in to comment.