Skip to content

Commit

Permalink
Merge pull request #683 from onflow/leo/extract-evm-state
Browse files Browse the repository at this point in the history
Extract EVM state
  • Loading branch information
zhangchiqing authored Dec 6, 2024
2 parents 4b32ea8 + bf84136 commit a540d9c
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 6 deletions.
80 changes: 80 additions & 0 deletions cmd/export/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package export

import (
"fmt"

"github.com/rs/zerolog/log"
"github.com/spf13/cobra"

"github.com/onflow/flow-evm-gateway/storage/pebble"
"github.com/onflow/flow-go/fvm/evm"
"github.com/onflow/flow-go/fvm/evm/emulator/state"
"github.com/onflow/flow-go/fvm/evm/offchain/storage"
flowGo "github.com/onflow/flow-go/model/flow"
)

var Cmd = &cobra.Command{
Use: "export-evm-state",
Short: "Export EVM state at a specific height",
RunE: func(*cobra.Command, []string) error {
if height == 0 || outputDir == "" || registerStoreDir == "" {
return fmt.Errorf("all flags (height, output, register-store) must be provided")
}

log.Info().Msgf("exporting EVM state for height %v from registerStoreDir %v, outputDir: %v, chain: %v", height, registerStoreDir, outputDir, chain)

chainID := flowGo.ChainID(chain)

err := ExportEVMStateForHeight(height, outputDir, registerStoreDir, chainID)
if err != nil {
return fmt.Errorf("fail to export: %w", err)
}

log.Info().Msgf("successfully exported EVM state to %v", outputDir)

return nil
},
}

var (
height uint64
outputDir string
chain string
registerStoreDir string
)

func init() {
Cmd.Flags().Uint64Var(&height, "evm-height", 0, "EVM Block height for EVM state export")
Cmd.Flags().StringVar(&outputDir, "output", "", "Output directory for exported EVM state")
Cmd.Flags().StringVar(&chain, "chain-id", "testnet", "Chain ID for the EVM state")
Cmd.Flags().StringVar(&registerStoreDir, "register-store", "", "Directory of the register store")
}

func ExportEVMStateForHeight(height uint64, outputDir string, registerStoreDir string, chainID flowGo.ChainID) error {
storageAddress := evm.StorageAccountAddress(chainID)

pebbleDB, err := pebble.OpenDB(registerStoreDir)
if err != nil {
return fmt.Errorf("failed to open pebble db: %w", err)
}

store := pebble.New(pebbleDB, log.Logger)
registerStore := pebble.NewRegisterStorage(store, storageAddress)
snapshot, err := registerStore.GetSnapshotAt(height)
if err != nil {
return err
}

ledger := storage.NewReadOnlyStorage(snapshot)
exporter, err := state.NewExporter(ledger, storageAddress)
if err != nil {
return err
}

err = exporter.ExportGob(outputDir)
if err != nil {
return err
}

return nil
}
2 changes: 2 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"os"

"github.com/onflow/flow-evm-gateway/cmd/export"
"github.com/onflow/flow-evm-gateway/cmd/run"
"github.com/onflow/flow-evm-gateway/cmd/version"
"github.com/rs/zerolog/log"
Expand All @@ -23,6 +24,7 @@ func Execute() {

func main() {
rootCmd.AddCommand(version.Cmd)
rootCmd.AddCommand(export.Cmd)
rootCmd.AddCommand(run.Cmd)

Execute()
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1
github.com/onflow/atree v0.8.0
github.com/onflow/cadence v1.2.2
github.com/onflow/flow-go v0.38.0-preview.0.0.20241125190444-25a8af57bea1
github.com/onflow/flow-go v0.38.0-preview.0.4
github.com/onflow/flow-go-sdk v1.2.3
github.com/onflow/go-ethereum v1.14.7
github.com/prometheus/client_golang v1.18.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -535,8 +535,8 @@ github.com/onflow/flow-ft/lib/go/contracts v1.0.1 h1:Ts5ob+CoCY2EjEd0W6vdLJ7hLL3
github.com/onflow/flow-ft/lib/go/contracts v1.0.1/go.mod h1:PwsL8fC81cjnUnTfmyL/HOIyHnyaw/JA474Wfj2tl6A=
github.com/onflow/flow-ft/lib/go/templates v1.0.1 h1:FDYKAiGowABtoMNusLuRCILIZDtVqJ/5tYI4VkF5zfM=
github.com/onflow/flow-ft/lib/go/templates v1.0.1/go.mod h1:uQ8XFqmMK2jxyBSVrmyuwdWjTEb+6zGjRYotfDJ5pAE=
github.com/onflow/flow-go v0.38.0-preview.0.0.20241125190444-25a8af57bea1 h1:tE21Kgx2Aqll9ywbiRDfc2BVIz5g6zKdrIom9U9eTE4=
github.com/onflow/flow-go v0.38.0-preview.0.0.20241125190444-25a8af57bea1/go.mod h1:c4ubAQ2WIMYY/TOaBvbajROEFWv2HwhKeGOsEdLPIM0=
github.com/onflow/flow-go v0.38.0-preview.0.4 h1:vjnp6btehu3X/aYjsXYlA3r/GGYeB05so0d7ICtXbmg=
github.com/onflow/flow-go v0.38.0-preview.0.4/go.mod h1:c4ubAQ2WIMYY/TOaBvbajROEFWv2HwhKeGOsEdLPIM0=
github.com/onflow/flow-go-sdk v1.2.3 h1:jb+0dIXBO12Zt8x3c2xDXYPv6k3sRTUvhe59M+EcXTI=
github.com/onflow/flow-go-sdk v1.2.3/go.mod h1:jMaffBTlAIdutx+pBhRIigLZFIBYSDDST0Uax1rW2qo=
github.com/onflow/flow-nft/lib/go/contracts v1.2.2 h1:XFERNVUDGbZ4ViZjt7P1cGD80mO1PzUJYPfdhXFsGbQ=
Expand Down
36 changes: 36 additions & 0 deletions services/evm/extract.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package evm

import (
"fmt"

"github.com/onflow/flow-evm-gateway/storage/pebble"
"github.com/onflow/flow-go/fvm/evm"
"github.com/onflow/flow-go/fvm/evm/emulator/state"
"github.com/onflow/flow-go/fvm/evm/offchain/storage"
flowGo "github.com/onflow/flow-go/model/flow"
)

func ExtractEVMState(
chainID flowGo.ChainID,
evmHeight uint64,
store *pebble.Storage,
) (*state.EVMState, error) {
storageRoot := evm.StorageAccountAddress(chainID)
registerStore := pebble.NewRegisterStorage(store, storageRoot)
snapshot, err := registerStore.GetSnapshotAt(evmHeight)
if err != nil {
return nil, fmt.Errorf("failed to get snapshot at evm height %d: %w", evmHeight, err)
}

ledger := storage.NewReadOnlyStorage(snapshot)
bv, err := state.NewBaseView(ledger, storageRoot)
if err != nil {
return nil, fmt.Errorf("failed to create base view: %w", err)
}

evmState, err := state.Extract(storageRoot, bv)
if err != nil {
return nil, err
}
return evmState, nil
}
46 changes: 46 additions & 0 deletions services/evm/extract_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package evm_test

import (
"fmt"
"testing"

"github.com/onflow/flow-evm-gateway/storage/pebble"
"github.com/onflow/flow-go/fvm/evm/emulator/state"
flowGo "github.com/onflow/flow-go/model/flow"
"github.com/rs/zerolog/log"
"github.com/stretchr/testify/require"

evmState "github.com/onflow/flow-evm-gateway/services/evm"
)

func StateDiff(t *testing.T) {
state1 := extractEVMState(t, flowGo.Testnet, "/var/flow52/evm/data/db", uint64(17724990))
state2 := evmStateFromCheckpointExtract(t, "/var/flow52/evm-state-from-checkpoint-228901661")

differences := state.Diff(state1, state2)

for i, diff := range differences {
fmt.Printf("Difference %d: %v\n", i, diff)
}

require.Len(t, differences, 0)
}

func extractEVMState(
t *testing.T, chainID flowGo.ChainID,
registerStoreDir string, evmHeight uint64) *state.EVMState {

pebbleDB, err := pebble.OpenDB(registerStoreDir)
require.NoError(t, err)
store := pebble.New(pebbleDB, log.Logger)

evmState, err := evmState.ExtractEVMState(chainID, evmHeight, store)
require.NoError(t, err)
return evmState
}

func evmStateFromCheckpointExtract(t *testing.T, dir string) *state.EVMState {
enState, err := state.ImportEVMStateFromGob(dir)
require.NoError(t, err)
return enState
}
2 changes: 1 addition & 1 deletion tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/onflow/crypto v0.25.2
github.com/onflow/flow-emulator v1.1.1-0.20241125195348-4e121ffb12af
github.com/onflow/flow-evm-gateway v0.0.0-20240201154855-4d4d3d3f19c7
github.com/onflow/flow-go v0.38.0-preview.0.0.20241125190444-25a8af57bea1
github.com/onflow/flow-go v0.38.0-preview.0.4
github.com/onflow/flow-go-sdk v1.2.3
github.com/onflow/go-ethereum v1.14.7
github.com/rs/zerolog v1.33.0
Expand Down
4 changes: 2 additions & 2 deletions tests/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -799,8 +799,8 @@ github.com/onflow/flow-ft/lib/go/contracts v1.0.1 h1:Ts5ob+CoCY2EjEd0W6vdLJ7hLL3
github.com/onflow/flow-ft/lib/go/contracts v1.0.1/go.mod h1:PwsL8fC81cjnUnTfmyL/HOIyHnyaw/JA474Wfj2tl6A=
github.com/onflow/flow-ft/lib/go/templates v1.0.1 h1:FDYKAiGowABtoMNusLuRCILIZDtVqJ/5tYI4VkF5zfM=
github.com/onflow/flow-ft/lib/go/templates v1.0.1/go.mod h1:uQ8XFqmMK2jxyBSVrmyuwdWjTEb+6zGjRYotfDJ5pAE=
github.com/onflow/flow-go v0.38.0-preview.0.0.20241125190444-25a8af57bea1 h1:tE21Kgx2Aqll9ywbiRDfc2BVIz5g6zKdrIom9U9eTE4=
github.com/onflow/flow-go v0.38.0-preview.0.0.20241125190444-25a8af57bea1/go.mod h1:c4ubAQ2WIMYY/TOaBvbajROEFWv2HwhKeGOsEdLPIM0=
github.com/onflow/flow-go v0.38.0-preview.0.4 h1:vjnp6btehu3X/aYjsXYlA3r/GGYeB05so0d7ICtXbmg=
github.com/onflow/flow-go v0.38.0-preview.0.4/go.mod h1:c4ubAQ2WIMYY/TOaBvbajROEFWv2HwhKeGOsEdLPIM0=
github.com/onflow/flow-go-sdk v1.2.3 h1:jb+0dIXBO12Zt8x3c2xDXYPv6k3sRTUvhe59M+EcXTI=
github.com/onflow/flow-go-sdk v1.2.3/go.mod h1:jMaffBTlAIdutx+pBhRIigLZFIBYSDDST0Uax1rW2qo=
github.com/onflow/flow-nft/lib/go/contracts v1.2.2 h1:XFERNVUDGbZ4ViZjt7P1cGD80mO1PzUJYPfdhXFsGbQ=
Expand Down

0 comments on commit a540d9c

Please sign in to comment.