Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract EVM state #683

Merged
merged 22 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading