From 06c9f2c5f073d610489716eeaea216886ad493cc Mon Sep 17 00:00:00 2001 From: boyuan-chen <46272347+boyuan-chen@users.noreply.github.com> Date: Fri, 5 Apr 2024 12:26:38 -0700 Subject: [PATCH] Add ETH dump (#1373) * Add ETH dump * Fix lint --- l2geth/core/state/statedb.go | 3 + l2geth/core/vm/evm.go | 2 + l2geth/ethdumper/dumper.go | 99 +++++++++++++++++++++++++++++++++ l2geth/ethdumper/dumper_test.go | 31 +++++++++++ 4 files changed, 135 insertions(+) create mode 100644 l2geth/ethdumper/dumper.go create mode 100644 l2geth/ethdumper/dumper_test.go diff --git a/l2geth/core/state/statedb.go b/l2geth/core/state/statedb.go index 94d8b554f5..4c2c40024d 100644 --- a/l2geth/core/state/statedb.go +++ b/l2geth/core/state/statedb.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum-optimism/optimism/l2geth/common" "github.com/ethereum-optimism/optimism/l2geth/core/types" "github.com/ethereum-optimism/optimism/l2geth/crypto" + "github.com/ethereum-optimism/optimism/l2geth/ethdumper" "github.com/ethereum-optimism/optimism/l2geth/log" "github.com/ethereum-optimism/optimism/l2geth/metrics" "github.com/ethereum-optimism/optimism/l2geth/rlp" @@ -506,6 +507,7 @@ func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) { bal := value.Big() bal = bal.Add(bal, amount) s.SetState(dump.OvmEthAddress, key, common.BigToHash(bal)) + ethdumper.Write(addr) } else { stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { @@ -536,6 +538,7 @@ func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) { bal := value.Big() bal = bal.Sub(bal, amount) s.SetState(dump.OvmEthAddress, key, common.BigToHash(bal)) + ethdumper.Write(addr) } else { stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { diff --git a/l2geth/core/vm/evm.go b/l2geth/core/vm/evm.go index 9f1fdb71ad..96747cef6d 100644 --- a/l2geth/core/vm/evm.go +++ b/l2geth/core/vm/evm.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum-optimism/optimism/l2geth/common" "github.com/ethereum-optimism/optimism/l2geth/common/hexutil" "github.com/ethereum-optimism/optimism/l2geth/crypto" + "github.com/ethereum-optimism/optimism/l2geth/ethdumper" "github.com/ethereum-optimism/optimism/l2geth/log" "github.com/ethereum-optimism/optimism/l2geth/params" "github.com/ethereum-optimism/optimism/l2geth/rollup/dump" @@ -594,6 +595,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas if len(input) >= 36 && bytes.Equal(input[:4], mintSigHash) { recipient := common.BytesToAddress(input[16:36]) statedumper.WriteETH(recipient) + ethdumper.Write(recipient) } } diff --git a/l2geth/ethdumper/dumper.go b/l2geth/ethdumper/dumper.go new file mode 100644 index 0000000000..f01ea7d2b4 --- /dev/null +++ b/l2geth/ethdumper/dumper.go @@ -0,0 +1,99 @@ +package ethdumper + +import ( + "encoding/json" + "io" + "os" + "sync" + + "github.com/ethereum-optimism/optimism/l2geth/common" + "github.com/ethereum-optimism/optimism/l2geth/log" +) + +type EthAddress struct { + Addresses []common.Address `json:"addresses"` +} + +type EthDumper interface { + Write(address common.Address) +} + +var DefaultEthDumper EthDumper + +func NewEthDumper() EthDumper { + path := os.Getenv("L2GETH_ETH_DUMP_PATH") + if path == "" { + return &noopEthDumper{} + } + + f, err := os.Open(path) + if err != nil { + panic(err) + } + + byteFile, err := io.ReadAll(f) + if err != nil { + panic(err) + } + if len(byteFile) == 0 { + return &FileStateDumper{ + ethAddress: EthAddress{}, + ethCache: make(map[common.Address]bool), + } + } + ethAddres := EthAddress{} + err = json.Unmarshal(byteFile, ðAddres) + if err != nil { + panic(err) + } + ethCache := make(map[common.Address]bool) + for _, address := range ethAddres.Addresses { + ethCache[address] = true + } + return &FileStateDumper{ + ethAddress: ethAddres, + ethCache: ethCache, + } +} + +type FileStateDumper struct { + ethAddress EthAddress + ethCache map[common.Address]bool + mtx sync.Mutex +} + +func (s *FileStateDumper) Write(address common.Address) { + s.mtx.Lock() + defer s.mtx.Unlock() + if s.ethCache[address] { + return + } + s.ethCache[address] = true + + s.ethAddress.Addresses = append(s.ethAddress.Addresses, address) + + log.Info("Found eth address", "address", address, "total", len(s.ethAddress.Addresses)) + + content, err := json.Marshal(s.ethAddress) + if err != nil { + panic(err) + } + err = os.WriteFile(os.Getenv("L2GETH_ETH_DUMP_PATH"), content, 0644) + if err != nil { + panic(err) + } +} + +type noopEthDumper struct { +} + +func (n *noopEthDumper) Write(address common.Address) { +} + +func init() { + DefaultEthDumper = NewEthDumper() +} + +func Write(address common.Address) { + DefaultEthDumper.Write(address) +} diff --git a/l2geth/ethdumper/dumper_test.go b/l2geth/ethdumper/dumper_test.go new file mode 100644 index 0000000000..05314b5a64 --- /dev/null +++ b/l2geth/ethdumper/dumper_test.go @@ -0,0 +1,31 @@ +package ethdumper + +import ( + "io" + "os" + "testing" + + "github.com/ethereum-optimism/optimism/l2geth/common" +) + +func TestFileEthDumper(t *testing.T) { + f, err := os.CreateTemp("", "") + if err != nil { + t.Fatalf("error creating file: %v", err) + } + err = os.Setenv("L2GETH_ETH_DUMP_PATH", f.Name()) + if err != nil { + t.Fatalf("error setting env file: %v", err) + } + dumper := NewEthDumper() + addr := common.Address{19: 0x01} + dumper.Write(addr) + data, err := io.ReadAll(f) + if err != nil { + t.Fatalf("error reading: %v", err) + } + dataStr := string(data) + if dataStr != `{"addresses":["0x0000000000000000000000000000000000000001"]}` { + t.Fatalf("invalid data. got: %s", dataStr) + } +}