Skip to content
Prev Previous commit
Next Next commit
revert changes
  • Loading branch information
tac0turtle committed Dec 18, 2025
commit c74e7f58d50e09286517d16b179ecee34c5be5f9
6 changes: 1 addition & 5 deletions block/internal/executing/executor.go
Comment thread
tac0turtle marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,6 @@ func (e *Executor) produceBlock() error {
if err = batch.SaveBlockData(header, data, &types.Signature{}); err != nil {
return fmt.Errorf("failed to save block data: %w", err)
}

if err = batch.Commit(); err != nil {
return fmt.Errorf("failed to commit early save batch: %w", err)
}
Expand Down Expand Up @@ -625,10 +624,7 @@ func (e *Executor) signHeader(header types.Header) (types.Signature, error) {
}

// executeTxsWithRetry executes transactions with retry logic.
// Idempotent execution and crash recovery are handled by the execution client
// (e.g., EngineClient) via ExecMeta tracking.
// NOTE: the function retries the execution client call regardless of the error.
// Some execution client errors are irrecoverable, and will eventually halt the node, as expected.
// NOTE: the function retries the execution client call regardless of the error. Some execution clients errors are irrecoverable, and will eventually halt the node, as expected.
func (e *Executor) executeTxsWithRetry(ctx context.Context, rawTxs [][]byte, header types.Header, currentState types.State) ([]byte, error) {
for attempt := 1; attempt <= common.MaxRetriesBeforeHalt; attempt++ {
newAppHash, _, err := e.exec.ExecuteTxs(ctx, rawTxs, header.Height(), header.Time(), currentState.AppHash)
Expand Down
5 changes: 0 additions & 5 deletions block/internal/executing/executor_logic_test.go
Comment thread
tac0turtle marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
Expand Up @@ -297,13 +297,8 @@ func TestExecutor_executeTxsWithRetry(t *testing.T) {
mockExec := testmocks.NewMockExecutor(t)
tt.setupMock(mockExec)

// Use an in-memory store for the test (needed for GetExecMeta)
ds := sync.MutexWrap(datastore.NewMapDatastore())
memStore := store.New(ds)

e := &Executor{
exec: mockExec,
store: memStore,
ctx: execCtx,
logger: zerolog.Nop(),
}
Expand Down
45 changes: 14 additions & 31 deletions execution/evm/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
ds "github.com/ipfs/go-datastore"
"github.com/golang-jwt/jwt/v5"
"github.com/rs/zerolog"

"github.com/evstack/ev-node/core/execution"
"github.com/evstack/ev-node/pkg/store"
)

const (
Expand Down Expand Up @@ -137,7 +137,7 @@ type EngineClient struct {

// store provides persistence for ExecMeta to enable idempotent execution
// and crash recovery. Optional - if nil, ExecMeta tracking is disabled.
store store.Store
store *EVMStore

mu sync.Mutex // Mutex to protect concurrent access to block hashes
currentHeadBlockHash common.Hash // Store last non-finalized HeadBlockHash
Expand All @@ -150,15 +150,16 @@ type EngineClient struct {
}

// NewEngineExecutionClient creates a new instance of EngineAPIExecutionClient.
// The store parameter is optional - if provided, ExecMeta tracking is enabled
// for idempotent execution and crash recovery.
// The db parameter is required for ExecMeta tracking which enables idempotent
// execution and crash recovery. The db is wrapped with a prefix to isolate
// EVM execution data from other ev-node data.
func NewEngineExecutionClient(
ethURL,
engineURL string,
jwtSecret string,
genesisHash common.Hash,
feeRecipient common.Address,
evStore store.Store,
db ds.Batching,
) (*EngineClient, error) {
ethClient, err := ethclient.Dial(ethURL)
if err != nil {
Expand Down Expand Up @@ -191,7 +192,7 @@ func NewEngineExecutionClient(
ethClient: ethClient,
genesisHash: genesisHash,
feeRecipient: feeRecipient,
store: evStore,
store: NewEVMStore(db),
currentHeadBlockHash: genesisHash,
currentSafeBlockHash: genesisHash,
currentFinalizedBlockHash: genesisHash,
Expand All @@ -205,13 +206,6 @@ func (c *EngineClient) SetLogger(l zerolog.Logger) {
c.logger = l
}

// SetStore allows callers to attach a store for ExecMeta tracking.
// This enables idempotent execution and crash recovery features.
// Must be called before ExecuteTxs if ExecMeta tracking is desired.
func (c *EngineClient) SetStore(s store.Store) {
c.store = s
}

// InitChain initializes the blockchain with the given genesis parameters
func (c *EngineClient) InitChain(ctx context.Context, genesisTime time.Time, initialHeight uint64, chainID string) ([]byte, uint64, error) {
if initialHeight != 1 {
Expand Down Expand Up @@ -396,7 +390,7 @@ func (c *EngineClient) ExecuteTxs(ctx context.Context, txs [][]byte, blockHeight
// Save ExecMeta with payloadID for crash recovery (Stage="started")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's remove this nil check and assume store is always set. it is in the constructor.

// This allows resuming the payload build if we crash before completing
if c.store != nil {
c.saveExecMeta(ctx, blockHeight, timestamp.Unix(), newPayloadID[:], nil, nil, txs, store.ExecStageStarted)
c.saveExecMeta(ctx, blockHeight, timestamp.Unix(), newPayloadID[:], nil, nil, txs, ExecStageStarted)
}

// 4. Process the payload (get, submit, finalize)
Expand Down Expand Up @@ -628,7 +622,7 @@ func (c *EngineClient) checkIdempotency(ctx context.Context, height uint64, time
execMeta, err := c.store.GetExecMeta(ctx, height)
if err == nil && execMeta != nil {
// If we already have a promoted block at this height, return the stored StateRoot
if execMeta.Stage == store.ExecStagePromoted && len(execMeta.StateRoot) > 0 {
if execMeta.Stage == ExecStagePromoted && len(execMeta.StateRoot) > 0 {
c.logger.Info().
Uint64("height", height).
Str("stage", execMeta.Stage).
Expand All @@ -637,7 +631,7 @@ func (c *EngineClient) checkIdempotency(ctx context.Context, height uint64, time
}

// If we have a started execution with a payloadID, return it to resume
if execMeta.Stage == store.ExecStageStarted && len(execMeta.PayloadID) == 8 {
if execMeta.Stage == ExecStageStarted && len(execMeta.PayloadID) == 8 {
c.logger.Info().
Uint64("height", height).
Str("stage", execMeta.Stage).
Expand Down Expand Up @@ -669,7 +663,7 @@ func (c *EngineClient) checkIdempotency(ctx context.Context, height uint64, time

// Update ExecMeta to promoted if store is configured
if c.store != nil {
c.saveExecMeta(ctx, height, timestamp.Unix(), nil, existingBlockHash[:], existingStateRoot.Bytes(), txs, store.ExecStagePromoted)
c.saveExecMeta(ctx, height, timestamp.Unix(), nil, existingBlockHash[:], existingStateRoot.Bytes(), txs, ExecStagePromoted)
}

return existingStateRoot.Bytes(), nil, true, nil
Expand Down Expand Up @@ -779,7 +773,7 @@ func (c *EngineClient) processPayload(ctx context.Context, payloadID engine.Payl

// 4. Save ExecMeta (Promoted)
if c.store != nil {
c.saveExecMeta(ctx, blockHeight, blockTimestamp, payloadID[:], blockHash[:], payloadResult.ExecutionPayload.StateRoot.Bytes(), txs, store.ExecStagePromoted)
c.saveExecMeta(ctx, blockHeight, blockTimestamp, payloadID[:], blockHash[:], payloadResult.ExecutionPayload.StateRoot.Bytes(), txs, ExecStagePromoted)
}

return payloadResult.ExecutionPayload.StateRoot.Bytes(), payloadResult.ExecutionPayload.GasUsed, nil
Expand All @@ -806,7 +800,7 @@ func (c *EngineClient) saveExecMeta(ctx context.Context, height uint64, timestam
return
}

execMeta := &store.ExecMeta{
execMeta := &ExecMeta{
Height: height,
Timestamp: timestamp,
PayloadID: payloadID,
Expand All @@ -825,22 +819,11 @@ func (c *EngineClient) saveExecMeta(ctx context.Context, height uint64, timestam
execMeta.TxHash = h.Sum(nil)
}

batch, err := c.store.NewBatch(ctx)
if err != nil {
c.logger.Warn().Err(err).Uint64("height", height).Msg("saveExecMeta: failed to create batch")
return
}

if err := batch.SaveExecMeta(execMeta); err != nil {
if err := c.store.SaveExecMeta(ctx, execMeta); err != nil {
c.logger.Warn().Err(err).Uint64("height", height).Msg("saveExecMeta: failed to save exec meta")
return
}

if err := batch.Commit(); err != nil {
c.logger.Warn().Err(err).Uint64("height", height).Msg("saveExecMeta: failed to commit batch")
return
}

c.logger.Debug().
Uint64("height", height).
Str("stage", stage).
Expand Down
39 changes: 2 additions & 37 deletions execution/evm/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ require (
github.com/evstack/ev-node v0.0.0-00010101000000-000000000000
github.com/evstack/ev-node/core v1.0.0-beta.5
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/ipfs/go-datastore v0.9.0
github.com/rs/zerolog v1.34.0
github.com/stretchr/testify v1.11.1
google.golang.org/protobuf v1.36.10
)

require (
Expand All @@ -17,81 +19,44 @@ require (
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/bits-and-blooms/bitset v1.20.0 // indirect
github.com/celestiaorg/go-header v0.7.4 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/consensys/gnark-crypto v0.18.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // 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.4.0 // indirect
github.com/dgraph-io/badger/v4 v4.5.1 // indirect
github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emicklei/dot v1.6.2 // indirect
github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect
github.com/ethereum/go-verkle v0.2.2 // indirect
github.com/ferranbt/fastssz v0.1.4 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/google/flatbuffers v24.12.23+incompatible // indirect
github.com/google/uuid v1.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.2 // indirect
github.com/ipfs/go-cid v0.6.0 // indirect
github.com/ipfs/go-datastore v0.9.0 // indirect
github.com/ipfs/go-ds-badger4 v0.1.8 // indirect
github.com/ipfs/go-log/v2 v2.9.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-libp2p v0.46.0 // indirect
github.com/libp2p/go-libp2p-pubsub v0.15.0 // indirect
github.com/libp2p/go-msgio v0.3.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.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.16.1 // 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.10.0 // indirect
github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-multistream v0.6.1 // indirect
github.com/multiformats/go-varint v0.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/rs/cors v1.11.1 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.4.1 // indirect
)

replace github.com/evstack/ev-node/core => ../../core
Expand Down
Loading
Loading