-
Notifications
You must be signed in to change notification settings - Fork 179
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
Add verification tool for evm offchain replay #6755
Open
zhangchiqing
wants to merge
44
commits into
leo/add-testcase-for-offchain-evm-backward-compatibilities
Choose a base branch
from
leo/add-verify-evm-offchain-replay
base: leo/add-testcase-for-offchain-evm-backward-compatibilities
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
bf4cc9a
Add new websocket handler and skeleton for its deps
illia-malachyn c0e50cd
Merge branch 'master' into illia-malachyn/6617-new-ws-handler
illia-malachyn b76c811
fix issue after merge
illia-malachyn f88cf9b
generate mocks. add graceful shutdown for controller
illia-malachyn 29380d0
check err when closing conn
illia-malachyn b08370d
Fixed comments
illia-malachyn dbaa545
add additional space
illia-malachyn 8e21498
Merge branch 'master' into illia-malachyn/6617-new-ws-handler
illia-malachyn b30d63d
regen data provider mock
illia-malachyn 839c35c
rename concurrent map. add more todos for error handling
illia-malachyn 48aaa56
Fix comments
illia-malachyn b42d8a7
Merge branch 'master' into illia-malachyn/6617-new-ws-handler
illia-malachyn 006c80a
update height in comment
zhangchiqing c548363
Merge branch 'master' into illia-malachyn/6617-new-ws-handler
illia-malachyn 39a777a
add offchain block context creation method
janezpodhostnik 333cbe9
cleanup
janezpodhostnik f880fe7
add more details
janezpodhostnik 501d0ff
fix init
janezpodhostnik d4b7668
use new block contect in offchain package
janezpodhostnik f4654c8
add mainnet height
janezpodhostnik c5bde97
Merge pull request #6743 from onflow/leo/update-height-comment
zhangchiqing c38f6ce
Update engine/access/rest/websockets/handler.go
peterargue a3676ba
Merge pull request #6630 from The-K-R-O-K/illia-malachyn/6617-new-ws-…
peterargue 549c64f
apply review comments
janezpodhostnik e670c37
extract method for block hash correction
janezpodhostnik cadbde9
Merge branch 'master' into janez/offchain-block-context
j1010001 b3d0864
Merge pull request #6751 from onflow/janez/offchain-block-context
janezpodhostnik 9bf550c
add testcase for offchain evm backward compatibilities
zhangchiqing 27c0f3a
review comments
zhangchiqing 2af8179
add verify evm offchain replay util cmd
zhangchiqing 873c707
refactor serailization with gob
zhangchiqing 7be4840
add logging
zhangchiqing 8b08a31
update error message
zhangchiqing c5752a5
add register checks
zhangchiqing 17cc1a8
store block proposal in replay
zhangchiqing 0c7e532
fix tests
zhangchiqing 0548f6a
update error message
zhangchiqing 5a197b6
update error message
zhangchiqing af0cc4f
add account status updates
zhangchiqing 96b7fa1
update provider
zhangchiqing 67e32f7
update verifable keys
zhangchiqing c9bb7c1
update verifable keys
zhangchiqing f564161
skip register verification
zhangchiqing 20487a3
fix regresion
zhangchiqing File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package verify | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/rs/zerolog/log" | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/onflow/flow-go/model/flow" | ||
) | ||
|
||
var ( | ||
flagDatadir string | ||
flagExecutionDataDir string | ||
flagEVMStateGobDir string | ||
flagChain string | ||
flagFromTo string | ||
) | ||
|
||
// usage example | ||
// | ||
// ./util verify-evm-offchain-replay --chain flow-testnet --from-to 211176671-211177000 | ||
// --datadir /var/flow/data/protocol --execution_data_dir /var/flow/data/execution_data | ||
var Cmd = &cobra.Command{ | ||
Use: "verify-evm-offchain-replay", | ||
Short: "verify evm offchain replay with execution data", | ||
Run: run, | ||
} | ||
|
||
func init() { | ||
Cmd.Flags().StringVar(&flagChain, "chain", "", "Chain name") | ||
_ = Cmd.MarkFlagRequired("chain") | ||
|
||
Cmd.Flags().StringVar(&flagDatadir, "datadir", "/var/flow/data/protocol", | ||
"directory that stores the protocol state") | ||
|
||
Cmd.Flags().StringVar(&flagExecutionDataDir, "execution_data_dir", "/var/flow/data/execution_data", | ||
"directory that stores the execution state") | ||
|
||
Cmd.Flags().StringVar(&flagFromTo, "from_to", "", | ||
"the flow height range to verify blocks, i.e, 1-1000, 1000-2000, 2000-3000, etc.") | ||
|
||
Cmd.Flags().StringVar(&flagEVMStateGobDir, "evm_state_gob_dir", "/var/flow/data/evm_state_gob", | ||
"directory that stores the evm state gob files as checkpoint") | ||
} | ||
|
||
func run(*cobra.Command, []string) { | ||
_ = flow.ChainID(flagChain).Chain() | ||
|
||
from, to, err := parseFromTo(flagFromTo) | ||
if err != nil { | ||
log.Fatal().Err(err).Msg("could not parse from_to") | ||
} | ||
|
||
log.Info().Msgf("verifying range from %d to %d", from, to) | ||
err = Verify(log.Logger, from, to, flow.Testnet, flagDatadir, flagExecutionDataDir, flagEVMStateGobDir) | ||
if err != nil { | ||
log.Fatal().Err(err).Msg("could not verify height") | ||
} | ||
log.Info().Msgf("successfully verified range from %d to %d", from, to) | ||
|
||
} | ||
|
||
func parseFromTo(fromTo string) (from, to uint64, err error) { | ||
parts := strings.Split(fromTo, "-") | ||
if len(parts) != 2 { | ||
return 0, 0, fmt.Errorf("invalid format: expected 'from-to', got '%s'", fromTo) | ||
} | ||
|
||
from, err = strconv.ParseUint(strings.TrimSpace(parts[0]), 10, 64) | ||
if err != nil { | ||
return 0, 0, fmt.Errorf("invalid 'from' value: %w", err) | ||
} | ||
|
||
to, err = strconv.ParseUint(strings.TrimSpace(parts[1]), 10, 64) | ||
if err != nil { | ||
return 0, 0, fmt.Errorf("invalid 'to' value: %w", err) | ||
} | ||
|
||
if from > to { | ||
return 0, 0, fmt.Errorf("'from' value (%d) must be less than or equal to 'to' value (%d)", from, to) | ||
} | ||
|
||
return from, to, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package verify | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/dgraph-io/badger/v2" | ||
badgerds "github.com/ipfs/go-ds-badger2" | ||
"github.com/rs/zerolog" | ||
|
||
"github.com/onflow/flow-go/cmd/util/cmd/common" | ||
"github.com/onflow/flow-go/fvm/environment" | ||
"github.com/onflow/flow-go/fvm/evm" | ||
"github.com/onflow/flow-go/fvm/evm/offchain/utils" | ||
"github.com/onflow/flow-go/fvm/evm/testutils" | ||
"github.com/onflow/flow-go/model/flow" | ||
"github.com/onflow/flow-go/module/blobs" | ||
"github.com/onflow/flow-go/module/executiondatasync/execution_data" | ||
"github.com/onflow/flow-go/storage" | ||
) | ||
|
||
// Verify verifies the offchain replay of EVM blocks from the given height range | ||
// and updates the EVM state gob files with the latest state | ||
func Verify(log zerolog.Logger, from uint64, to uint64, chainID flow.ChainID, dataDir string, executionDataDir string, evmStateGobDir string) error { | ||
log.Info(). | ||
Str("chain", chainID.String()). | ||
Str("dataDir", dataDir). | ||
Str("executionDataDir", executionDataDir). | ||
Str("evmStateGobDir", evmStateGobDir). | ||
Msgf("verifying range from %d to %d", from, to) | ||
|
||
db, storages, executionDataStore, dsStore, err := initStorages(chainID, dataDir, executionDataDir) | ||
if err != nil { | ||
return fmt.Errorf("could not initialize storages: %w", err) | ||
} | ||
|
||
defer db.Close() | ||
defer dsStore.Close() | ||
|
||
var store *testutils.TestValueStore | ||
isRoot := isEVMRootHeight(chainID, from) | ||
if isRoot { | ||
log.Info().Msgf("initializing EVM state for root height %d", from) | ||
|
||
store = testutils.GetSimpleValueStore() | ||
as := environment.NewAccountStatus() | ||
rootAddr := evm.StorageAccountAddress(chainID) | ||
err = store.SetValue(rootAddr[:], []byte(flow.AccountStatusKey), as.ToBytes()) | ||
if err != nil { | ||
return err | ||
} | ||
} else { | ||
prev := from - 1 | ||
log.Info().Msgf("loading EVM state from previous height %d", prev) | ||
|
||
valueFileName, allocatorFileName := evmStateGobFileNamesByEndHeight(evmStateGobDir, prev) | ||
values, err := testutils.DeserializeState(valueFileName) | ||
if err != nil { | ||
return fmt.Errorf("could not deserialize state %v: %w", valueFileName, err) | ||
} | ||
|
||
allocators, err := testutils.DeserializeAllocator(allocatorFileName) | ||
if err != nil { | ||
return fmt.Errorf("could not deserialize allocator %v: %w", allocatorFileName, err) | ||
} | ||
store = testutils.GetSimpleValueStorePopulated(values, allocators) | ||
} | ||
|
||
err = utils.OffchainReplayBackwardCompatibilityTest( | ||
log, | ||
chainID, | ||
from, | ||
to, | ||
storages.Headers, | ||
storages.Results, | ||
executionDataStore, | ||
store, | ||
) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
valueFileName, allocatorFileName := evmStateGobFileNamesByEndHeight(evmStateGobDir, to) | ||
values, allocators := store.Dump() | ||
err = testutils.SerializeState(valueFileName, values) | ||
if err != nil { | ||
return err | ||
} | ||
err = testutils.SerializeAllocator(allocatorFileName, allocators) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
log.Info().Msgf("saved EVM state to %s and %s", valueFileName, allocatorFileName) | ||
|
||
return nil | ||
} | ||
|
||
func initStorages(chainID flow.ChainID, dataDir string, executionDataDir string) ( | ||
*badger.DB, | ||
*storage.All, | ||
execution_data.ExecutionDataGetter, | ||
io.Closer, | ||
error, | ||
) { | ||
db := common.InitStorage(dataDir) | ||
|
||
storages := common.InitStorages(db) | ||
|
||
datastoreDir := filepath.Join(executionDataDir, "blobstore") | ||
err := os.MkdirAll(datastoreDir, 0700) | ||
if err != nil { | ||
return nil, nil, nil, nil, err | ||
} | ||
dsOpts := &badgerds.DefaultOptions | ||
ds, err := badgerds.NewDatastore(datastoreDir, dsOpts) | ||
if err != nil { | ||
return nil, nil, nil, nil, err | ||
} | ||
|
||
executionDataBlobstore := blobs.NewBlobstore(ds) | ||
executionDataStore := execution_data.NewExecutionDataStore(executionDataBlobstore, execution_data.DefaultSerializer) | ||
|
||
return db, storages, executionDataStore, ds, nil | ||
} | ||
|
||
// EVM Root Height is the first block that has EVM Block Event where the EVM block height is 1 | ||
func isEVMRootHeight(chainID flow.ChainID, flowHeight uint64) bool { | ||
if chainID == flow.Testnet { | ||
return flowHeight == 211176671 | ||
} else if chainID == flow.Mainnet { | ||
return flowHeight == 85981136 | ||
} | ||
return flowHeight == 1 | ||
} | ||
|
||
func evmStateGobFileNamesByEndHeight(evmStateGobDir string, endHeight uint64) (string, string) { | ||
valueFileName := filepath.Join(evmStateGobDir, fmt.Sprintf("values-%d.gob", endHeight)) | ||
allocatorFileName := filepath.Join(evmStateGobDir, fmt.Sprintf("allocators-%d.gob", endHeight)) | ||
return valueFileName, allocatorFileName | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chain ID is not needed