Skip to content

Commit

Permalink
feat: evm client implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
jim380 committed Oct 29, 2024
1 parent 86bb3fb commit a28c3ca
Show file tree
Hide file tree
Showing 3 changed files with 891 additions and 2 deletions.
220 changes: 220 additions & 0 deletions execution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
package execution

import (
"context"
"errors"
"fmt"
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
execution "github.com/rollkit/go-execution"
rollkitTypes "github.com/rollkit/rollkit/types"
)

// Define necessary types and constants
type PayloadStatus string

const (
PayloadStatusValid PayloadStatus = "VALID"
PayloadStatusInvalid PayloadStatus = "INVALID"
PayloadStatusSyncing PayloadStatus = "SYNCING"
)

var (
ErrNilPayloadStatus = errors.New("nil payload status")
ErrInvalidPayloadStatus = errors.New("invalid payload status")
)

type EngineAPIExecutionClient struct {
ethClient *ethclient.Client
engineClient *rpc.Client
genesisHash common.Hash
feeRecipient common.Address
}

// NewEngineAPIExecutionClient creates a new instance of EngineAPIExecutionClient.
func NewEngineAPIExecutionClient(ethURL, engineURL string, genesisHash common.Hash, feeRecipient common.Address) (*EngineAPIExecutionClient, error) {
ethClient, err := ethclient.Dial(ethURL)
if err != nil {
return nil, fmt.Errorf("failed to connect to Ethereum client: %w", err)
}
engineClient, err := rpc.Dial(engineURL)
if err != nil {
return nil, fmt.Errorf("failed to connect to Engine API: %w", err)
}
return &EngineAPIExecutionClient{
ethClient: ethClient,
engineClient: engineClient,
genesisHash: genesisHash,
feeRecipient: feeRecipient,
}, nil
}

var _ execution.Execute = (*EngineAPIExecutionClient)(nil)

// InitChain initializes the blockchain with genesis information.
func (c *EngineAPIExecutionClient) InitChain(
genesisTime time.Time,
initialHeight uint64,
chainID string,
) (rollkitTypes.Hash, uint64, error) {
ctx := context.Background()
var forkchoiceResult map[string]interface{}
err := c.engineClient.CallContext(ctx, &forkchoiceResult, "engine_forkchoiceUpdatedV1",
map[string]interface{}{
"headBlockHash": c.genesisHash,
"safeBlockHash": c.genesisHash,
"finalizedBlockHash": c.genesisHash,
},
map[string]interface{}{
"timestamp": genesisTime.Unix(),
"prevRandao": common.Hash{}, // TO-DO
"suggestedFeeRecipient": c.feeRecipient,
},
)
if err != nil {
return rollkitTypes.Hash{}, 0, fmt.Errorf("engine_forkchoiceUpdatedV1 failed: %w", err)
}
payloadID, ok := forkchoiceResult["payloadId"].(string)
if !ok {
return rollkitTypes.Hash{}, 0, ErrNilPayloadStatus
}
var payload map[string]interface{}
err = c.engineClient.CallContext(ctx, &payload, "engine_getPayloadV1", payloadID)
if err != nil {
return rollkitTypes.Hash{}, 0, fmt.Errorf("engine_getPayloadV1 failed: %w", err)
}
stateRoot := common.HexToHash(payload["stateRoot"].(string))
gasLimit := uint64(payload["gasLimit"].(float64))
var rollkitStateRoot rollkitTypes.Hash
copy(rollkitStateRoot[:], stateRoot[:])
return rollkitStateRoot, gasLimit, nil
}

// GetTxs retrieves transactions from the transaction pool.
func (c *EngineAPIExecutionClient) GetTxs() ([]rollkitTypes.Tx, error) {
ctx := context.Background()
var result struct {
Pending map[string]map[string]*types.Transaction `json:"pending"`
Queued map[string]map[string]*types.Transaction `json:"queued"`
}
err := c.ethClient.Client().CallContext(ctx, &result, "txpool_content")
if err != nil {
return nil, fmt.Errorf("failed to get tx pool content: %w", err)
}
var txs []rollkitTypes.Tx
for _, accountTxs := range result.Pending {
for _, tx := range accountTxs {
txBytes, err := tx.MarshalBinary()
if err != nil {
return nil, fmt.Errorf("failed to marshal transaction: %w", err)
}
txs = append(txs, rollkitTypes.Tx(txBytes))
}
}
for _, accountTxs := range result.Queued {
for _, tx := range accountTxs {
txBytes, err := tx.MarshalBinary()
if err != nil {
return nil, fmt.Errorf("failed to marshal transaction: %w", err)
}
txs = append(txs, rollkitTypes.Tx(txBytes))
}
}
return txs, nil
}

// ExecuteTxs executes the given transactions and returns the new state root and gas used.
func (c *EngineAPIExecutionClient) ExecuteTxs(
txs []rollkitTypes.Tx,
blockHeight uint64,
timestamp time.Time,
prevStateRoot rollkitTypes.Hash,
) (rollkitTypes.Hash, uint64, error) {
ctx := context.Background()
ethTxs := make([][]byte, len(txs))
for i, tx := range txs {
ethTxs[i] = tx
}
prevRandao := c.derivePrevRandao(blockHeight)
var forkchoiceResult map[string]interface{}
err := c.engineClient.CallContext(ctx, &forkchoiceResult, "engine_forkchoiceUpdatedV1",
map[string]interface{}{
"headBlockHash": common.BytesToHash(prevStateRoot[:]),
"safeBlockHash": common.BytesToHash(prevStateRoot[:]),
"finalizedBlockHash": common.BytesToHash(prevStateRoot[:]),
},
map[string]interface{}{
"timestamp": timestamp.Unix(),
"prevRandao": prevRandao,
"suggestedFeeRecipient": c.feeRecipient,
},
)
if err != nil {
return rollkitTypes.Hash{}, 0, fmt.Errorf("engine_forkchoiceUpdatedV1 failed: %w", err)
}
payloadID, ok := forkchoiceResult["payloadId"].(string)
if !ok {
return rollkitTypes.Hash{}, 0, ErrNilPayloadStatus
}
var payload map[string]interface{}
err = c.engineClient.CallContext(ctx, &payload, "engine_getPayloadV1", payloadID)
if err != nil {
return rollkitTypes.Hash{}, 0, fmt.Errorf("engine_getPayloadV1 failed: %w", err)
}
payload["transactions"] = ethTxs
var newPayloadResult map[string]interface{}
err = c.engineClient.CallContext(ctx, &newPayloadResult, "engine_newPayloadV1", payload)
if err != nil {
return rollkitTypes.Hash{}, 0, fmt.Errorf("engine_newPayloadV1 failed: %w", err)
}
status, ok := newPayloadResult["status"].(string)
if !ok || PayloadStatus(status) != PayloadStatusValid {
return rollkitTypes.Hash{}, 0, ErrInvalidPayloadStatus
}
newStateRoot := common.HexToHash(payload["stateRoot"].(string))
gasUsed := uint64(payload["gasUsed"].(float64))
var rollkitNewStateRoot rollkitTypes.Hash
copy(rollkitNewStateRoot[:], newStateRoot[:])
return rollkitNewStateRoot, gasUsed, nil
}

// SetFinal marks a block at the given height as final.
func (c *EngineAPIExecutionClient) SetFinal(blockHeight uint64) error {
ctx := context.Background()
block, err := c.ethClient.BlockByNumber(ctx, big.NewInt(int64(blockHeight)))
if err != nil {
return fmt.Errorf("failed to get block at height %d: %w", blockHeight, err)
}
var result map[string]interface{}
err = c.engineClient.CallContext(ctx, &result, "engine_forkchoiceUpdatedV1",
map[string]interface{}{
"headBlockHash": block.Hash(),
"safeBlockHash": block.Hash(),
"finalizedBlockHash": block.Hash(),
},
nil, // No payload attributes for finalization
)
if err != nil {
return fmt.Errorf("engine_forkchoiceUpdatedV1 failed for finalization: %w", err)
}
payloadStatus, ok := result["payloadStatus"].(map[string]interface{})
if !ok {
return ErrNilPayloadStatus
}
status, ok := payloadStatus["status"].(string)
if !ok || PayloadStatus(status) != PayloadStatusValid {
return ErrInvalidPayloadStatus
}
return nil
}

// derivePrevRandao generates a deterministic prevRandao value based on block height.
func (c *EngineAPIExecutionClient) derivePrevRandao(blockHeight uint64) common.Hash {
// TO-DO
return common.BigToHash(big.NewInt(int64(blockHeight)))
}
108 changes: 106 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,107 @@
module github.com/rollkit/template-da-repo
module github.com/rollkit/go-execution-evm

go 1.21.0
go 1.22.8

replace github.com/rollkit/go-execution => github.com/lastdotnet/go-execution v0.0.0-20241029045146-b7513b533b24

require (
github.com/ethereum/go-ethereum v1.14.11
github.com/rollkit/go-execution v0.0.0-00010101000000-000000000000
github.com/rollkit/rollkit v0.13.7
)

require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
github.com/celestiaorg/go-header v0.6.2 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cometbft/cometbft v0.38.7 // indirect
github.com/cometbft/cometbft-db v0.8.0 // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/cosmos/gogoproto v1.5.0 // indirect
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect
github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect
github.com/go-kit/kit v0.13.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.2.1 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/holiman/uint256 v1.3.1 // indirect
github.com/ipfs/go-cid v0.4.1 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-libp2p v0.35.0 // indirect
github.com/libp2p/go-libp2p-pubsub v0.11.0 // indirect
github.com/libp2p/go-msgio v0.3.0 // indirect
github.com/linxGnu/grocksdb v1.7.16 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/multiformats/go-multiaddr v0.13.0 // indirect
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-multibase v0.2.0 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect
github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-multistream v0.5.0 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.30.0 // indirect
github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.19.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/supranational/blst v0.3.13 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
go.etcd.io/bbolt v1.3.7 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.2.1 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
)
Loading

0 comments on commit a28c3ca

Please sign in to comment.