Commit 08833f84 authored by Andreas Bigger's avatar Andreas Bigger

Remove eof-crawler completely

parent 060841d0
# op-chain-ops
This package contains a number of state utilities.
This package contains utilities for working with chain state.
## check-l2
......@@ -23,25 +23,3 @@ that can be executed by providing the `--l1-rpc-url` and `--l2-rpc-url` flags.
--l2-rpc-url http://localhost:9545 \
--l1-rpc-url http://localhost:8545
```
## eof-crawler
Simple CLI tool to scan all accounts in a geth LevelDB
for contracts that begin with the EOF prefix.
#### Usage
It can be built and run using the [Makefile](./Makefile) `eof-crawler` target.
Run `make eof-crawler` to create a binary in [./bin/eof-crawler](./bin/eof-crawler)
that can be executed by providing the `--db-path` and optional `--out` flags.
1. Pass the directory of the Geth DB into the tool
```sh
./bin/eof-crawler/main.go \
--db-path <db_path> \
--out <out_file>
```
2. Once the indexing has completed, an array of all EOF-prefixed contracts
will be written to designated output file (`eof_contracts.json` by default).
package main
import (
"errors"
"os"
"github.com/mattn/go-isatty"
"github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/op-chain-ops/eof"
"github.com/ethereum/go-ethereum/log"
)
func main() {
log.Root().SetHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(isatty.IsTerminal(os.Stderr.Fd()))))
app := &cli.App{
Name: "eof-crawler",
Usage: "Scan a Geth database for EOF-prefixed contracts",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "db-path",
Usage: "Path to the geth LevelDB",
},
&cli.StringFlag{
Name: "out",
Value: "eof-contracts.json",
Usage: "Path to the output file",
},
},
Action: func(ctx *cli.Context) error {
dbPath := ctx.String("db-path")
if len(dbPath) == 0 {
return errors.New("Must specify a db-path")
}
out := ctx.String("out")
return eof.IndexEOFContracts(dbPath, out)
},
}
if err := app.Run(os.Args); err != nil {
log.Crit("error indexing state", "err", err)
}
}
package eof
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"log"
"os"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
)
// Account represents an account in the state.
type Account struct {
Balance string `json:"balance"`
Nonce uint64 `json:"nonce"`
Root hexutil.Bytes `json:"root"`
CodeHash hexutil.Bytes `json:"codeHash"`
Code hexutil.Bytes `json:"code,omitempty"`
Address common.Address `json:"address,omitempty"`
SecureKey hexutil.Bytes `json:"key,omitempty"`
}
// emptyCodeHash is the known hash of an account with no code.
var emptyCodeHash = crypto.Keccak256(nil)
// IndexEOFContracts indexes all the EOF contracts in the state trie of the head block
// for the given db and writes them to a JSON file.
func IndexEOFContracts(dbPath string, out string) error {
// Open an existing Ethereum database
db, err := rawdb.NewLevelDBDatabase(dbPath, 16, 16, "", true)
if err != nil {
return fmt.Errorf("Failed to open database: %w", err)
}
stateDB := state.NewDatabase(db)
// Retrieve the head block
hash := rawdb.ReadHeadBlockHash(db)
number := rawdb.ReadHeaderNumber(db, hash)
if number == nil {
return errors.New("Failed to retrieve head block number")
}
head := rawdb.ReadBlock(db, hash, *number)
if head == nil {
return errors.New("Failed to retrieve head block")
}
// Retrieve the state belonging to the head block
st, err := trie.New(trie.StateTrieID(head.Root()), trie.NewDatabase(db))
if err != nil {
return fmt.Errorf("Failed to retrieve state trie: %w", err)
}
log.Printf("Indexing state trie at head block #%d [0x%x]", *number, hash)
// Iterate over the entire account trie to search for EOF-prefixed contracts
start := time.Now()
missingPreimages := uint64(0)
eoas := uint64(0)
nonEofContracts := uint64(0)
eofContracts := make([]Account, 0)
it := trie.NewIterator(st.NodeIterator(nil))
for it.Next() {
// Decode the state account
var data types.StateAccount
err := rlp.DecodeBytes(it.Value, &data)
if err != nil {
return fmt.Errorf("Failed to decode state account: %w", err)
}
// Check to see if the account has any code associated with it before performing
// more reads from the trie & db.
if bytes.Equal(data.CodeHash, emptyCodeHash) {
eoas++
continue
}
// Create a serializable `Account` object
account := Account{
Balance: data.Balance.String(),
Nonce: data.Nonce,
Root: data.Root[:],
CodeHash: data.CodeHash,
SecureKey: it.Key,
}
// Attempt to get the address of the account from the trie
addrBytes, err := st.Get(it.Key)
if err != nil {
return fmt.Errorf("load address for account: %w", err)
}
if addrBytes == nil {
// Preimage missing! Cannot continue.
missingPreimages++
continue
}
addr := common.BytesToAddress(addrBytes)
// Attempt to get the code of the account from the trie
code, err := stateDB.ContractCode(crypto.Keccak256Hash(addrBytes), common.BytesToHash(data.CodeHash))
if err != nil {
return fmt.Errorf("Could not load code for account %x: %w", addr, err)
}
// Check if the contract's runtime bytecode starts with the EOF prefix.
if len(code) >= 1 && code[0] == 0xEF {
// Append the account to the list of EOF contracts
account.Address = addr
account.Code = code
eofContracts = append(eofContracts, account)
} else {
nonEofContracts++
}
}
// Print finishing status
log.Printf("Indexing done in %v, found %d EOF contracts", time.Since(start), len(eofContracts))
log.Printf("Num missing preimages: %d", missingPreimages)
log.Printf("Non-EOF-prefixed contracts: %d", nonEofContracts)
log.Printf("Accounts with no code (EOAs): %d", eoas)
// Write the EOF contracts to a file
file, err := json.MarshalIndent(eofContracts, "", " ")
if err != nil {
return fmt.Errorf("Cannot marshal EOF contracts: %w", err)
}
err = os.WriteFile(out, file, 0644)
if err != nil {
return fmt.Errorf("Failed to write EOF contracts array to file: %w", err)
}
log.Printf("Wrote list of EOF contracts to `%v`", out)
return nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment