From 836459d68a8021accf285e6e9a503e5266140209 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Thu, 9 May 2024 16:20:53 -0600 Subject: [PATCH 01/15] init: open database with separate wasm dir --- cmd/nitro/init.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/nitro/init.go b/cmd/nitro/init.go index a45ec054a1..750bf03516 100644 --- a/cmd/nitro/init.go +++ b/cmd/nitro/init.go @@ -172,13 +172,13 @@ func validateBlockChain(blockChain *core.BlockChain, chainConfig *params.ChainCo func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeConfig, chainId *big.Int, cacheConfig *core.CacheConfig, l1Client arbutil.L1Interface, rollupAddrs chaininfo.RollupAddresses) (ethdb.Database, *core.BlockChain, error) { if !config.Init.Force { - if readOnlyDb, err := stack.OpenDatabaseWithFreezer("l2chaindata", 0, 0, "", "l2chaindata/", true); err == nil { + if readOnlyDb, err := stack.OpenDatabaseWithFreezerAndWasm("l2chaindata", "wasm", 0, 0, "", "l2chaindata/", true); err == nil { if chainConfig := gethexec.TryReadStoredChainConfig(readOnlyDb); chainConfig != nil { readOnlyDb.Close() if !arbmath.BigEquals(chainConfig.ChainID, chainId) { return nil, nil, fmt.Errorf("database has chain ID %v but config has chain ID %v (are you sure this database is for the right chain?)", chainConfig.ChainID, chainId) } - chainDb, err := stack.OpenDatabaseWithFreezer("l2chaindata", config.Execution.Caching.DatabaseCache, config.Persistent.Handles, config.Persistent.Ancient, "l2chaindata/", false) + chainDb, err := stack.OpenDatabaseWithFreezerAndWasm("l2chaindata", "wasm", config.Execution.Caching.DatabaseCache, config.Persistent.Handles, config.Persistent.Ancient, "l2chaindata/", false) if err != nil { return chainDb, nil, err } @@ -230,7 +230,7 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo var initDataReader statetransfer.InitDataReader = nil - chainDb, err := stack.OpenDatabaseWithFreezer("l2chaindata", config.Execution.Caching.DatabaseCache, config.Persistent.Handles, config.Persistent.Ancient, "l2chaindata/", false) + chainDb, err := stack.OpenDatabaseWithFreezerAndWasm("l2chaindata", "wasm", config.Execution.Caching.DatabaseCache, config.Persistent.Handles, config.Persistent.Ancient, "l2chaindata/", false) if err != nil { return chainDb, nil, err } From e03a347e055fe1995cf97621e0e57a91675ca42a Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Thu, 9 May 2024 16:22:05 -0600 Subject: [PATCH 02/15] program: recreate activated stylus entry if needed --- arbos/programs/native.go | 72 ++++++++++++++++++++++++++++++++++---- arbos/programs/programs.go | 8 ++++- arbos/programs/wasm.go | 5 +++ 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 123dda54ce..2fe4822fb6 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/log" @@ -53,6 +54,24 @@ func activateProgram( debug bool, burner burn.Burner, ) (*activationInfo, error) { + info, asm, module, err := activateProgramInternal(db, program, codehash, wasm, page_limit, version, debug, burner) + if err != nil { + return nil, err + } + db.ActivateWasm(info.moduleHash, asm, module) + return info, nil +} + +func activateProgramInternal( + db vm.StateDB, + program common.Address, + codehash common.Hash, + wasm []byte, + page_limit uint16, + version uint16, + debug bool, + burner burn.Burner, +) (*activationInfo, []byte, []byte, error) { output := &rustBytes{} asmLen := usize(0) moduleHash := &bytes32{} @@ -78,9 +97,9 @@ func activateProgram( log.Warn("activation failed", "err", err, "msg", msg, "program", program) } if errors.Is(err, vm.ErrExecutionReverted) { - return nil, fmt.Errorf("%w: %s", ErrProgramActivation, msg) + return nil, nil, nil, fmt.Errorf("%w: %s", ErrProgramActivation, msg) } - return nil, err + return nil, nil, nil, err } hash := moduleHash.toHash() @@ -95,13 +114,55 @@ func activateProgram( asmEstimate: uint32(stylusData.asm_estimate), footprint: uint16(stylusData.footprint), } - db.ActivateWasm(hash, asm, module) - return info, err + return info, asm, module, err +} + +func getLocalAsm(statedb vm.StateDB, moduleHash common.Hash, address common.Address, pagelimit uint16, time uint64, debugMode bool, program Program) ([]byte, error) { + localAsm, err := statedb.TryGetActivatedAsm(moduleHash) + if err == nil || len(localAsm) > 0 { + return localAsm, nil + } + + codeHash := statedb.GetCodeHash(address) + burner := burn.NewSystemBurner(nil, false) + + wasm, err := getWasm(statedb, address) + if err != nil { + return nil, err + } + + // we know program is activated, so it must be in correct version and not use too much memory + info, asm, module, err := activateProgramInternal(statedb, address, codeHash, wasm, pagelimit, program.version, debugMode, burner) + + if err != nil { + return nil, err + } + + if info.moduleHash != moduleHash { + return nil, errors.New("failed to re-activate program not found in database") + } + + currentHoursSince := hoursSinceArbitrum(time) + if currentHoursSince > program.activatedAt { + // stylus program is active on-chain, and was activated in the past + // so we store it directly to database + batch := statedb.Database().WasmStore().NewBatch() + rawdb.WriteActivation(batch, moduleHash, asm, module) + if err := batch.Write(); err != nil { + log.Error("failed writing re-activation to state", "address", address, "err", err) + } + } else { + // program activated recently, possibly in this eth_call + // store it to statedb. It will be stored to database if statedb is commited + statedb.ActivateWasm(info.moduleHash, asm, module) + } + return asm, nil } func callProgram( address common.Address, moduleHash common.Hash, + localAsm []byte, scope *vm.ScopeContext, interpreter *vm.EVMInterpreter, tracingInfo *util.TracingInfo, @@ -111,7 +172,6 @@ func callProgram( memoryModel *MemoryModel, ) ([]byte, error) { db := interpreter.Evm().StateDB - asm := db.GetActivatedAsm(moduleHash) debug := stylusParams.debugMode if db, ok := db.(*state.StateDB); ok { @@ -123,7 +183,7 @@ func callProgram( output := &rustBytes{} status := userStatus(C.stylus_call( - goSlice(asm), + goSlice(localAsm), goSlice(calldata), stylusParams.encode(), evmApi.cNative, diff --git a/arbos/programs/programs.go b/arbos/programs/programs.go index 779f2d6c67..b277f5d678 100644 --- a/arbos/programs/programs.go +++ b/arbos/programs/programs.go @@ -205,6 +205,12 @@ func (p Programs) CallProgram( statedb.AddStylusPages(program.footprint) defer statedb.SetStylusPagesOpen(open) + localAsm, err := getLocalAsm(statedb, moduleHash, contract.Address(), params.PageLimit, evm.Context.Time, debugMode, program) + if err != nil { + log.Crit("failed to get local wasm for activated program", "program", contract.Address()) + return nil, err + } + evmData := &evmData{ blockBasefee: common.BigToHash(evm.Context.BaseFee), chainId: evm.ChainConfig().ChainID.Uint64(), @@ -227,7 +233,7 @@ func (p Programs) CallProgram( if contract.CodeAddr != nil { address = *contract.CodeAddr } - return callProgram(address, moduleHash, scope, interpreter, tracingInfo, calldata, evmData, goParams, model) + return callProgram(address, moduleHash, localAsm, scope, interpreter, tracingInfo, calldata, evmData, goParams, model) } func getWasm(statedb vm.StateDB, program common.Address) ([]byte, error) { diff --git a/arbos/programs/wasm.go b/arbos/programs/wasm.go index 77eb7e0f2f..105516dc62 100644 --- a/arbos/programs/wasm.go +++ b/arbos/programs/wasm.go @@ -128,9 +128,14 @@ func startProgram(module uint32) uint32 //go:wasmimport programs send_response func sendResponse(req_id uint32) uint32 +func getLocalAsm(statedb vm.StateDB, moduleHash common.Hash, address common.Address, pagelimit uint16, debugMode bool, program Program) ([]byte, error) { + return nil, nil +} + func callProgram( address common.Address, moduleHash common.Hash, + _localAsm []byte, scope *vm.ScopeContext, interpreter *vm.EVMInterpreter, tracingInfo *util.TracingInfo, From a5b9853583e4947d0c1aed5a49778b8718b1dffc Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Thu, 9 May 2024 19:10:13 -0600 Subject: [PATCH 03/15] geth - support separate wasm --- go-ethereum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go-ethereum b/go-ethereum index 72f81daa8c..37b6489382 160000 --- a/go-ethereum +++ b/go-ethereum @@ -1 +1 @@ -Subproject commit 72f81daa8c59f044246b6e1f3eca08187edd7417 +Subproject commit 37b6489382bb884dd1216dcb0f6a224ce2ca5fe2 From c9d19bcdc0078dfe7321256bf35fb5085429c251 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Thu, 9 May 2024 19:32:32 -0600 Subject: [PATCH 04/15] wasm split: fix native --- arbos/programs/native.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 2fe4822fb6..b657472371 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -54,7 +54,7 @@ func activateProgram( debug bool, burner burn.Burner, ) (*activationInfo, error) { - info, asm, module, err := activateProgramInternal(db, program, codehash, wasm, page_limit, version, debug, burner) + info, asm, module, err := activateProgramInternal(db, program, codehash, wasm, page_limit, version, debug, burner.GasLeft()) if err != nil { return nil, err } @@ -70,7 +70,7 @@ func activateProgramInternal( page_limit uint16, version uint16, debug bool, - burner burn.Burner, + gasLeft *uint64, ) (*activationInfo, []byte, []byte, error) { output := &rustBytes{} asmLen := usize(0) @@ -88,7 +88,7 @@ func activateProgramInternal( &codeHash, moduleHash, stylusData, - (*u64)(burner.GasLeft()), + (*u64)(gasLeft), )) data, msg, err := status.toResult(output.intoBytes(), debug) @@ -124,15 +124,15 @@ func getLocalAsm(statedb vm.StateDB, moduleHash common.Hash, address common.Addr } codeHash := statedb.GetCodeHash(address) - burner := burn.NewSystemBurner(nil, false) wasm, err := getWasm(statedb, address) if err != nil { return nil, err } + unlimitedGas := uint64(0xffffffffffff) // we know program is activated, so it must be in correct version and not use too much memory - info, asm, module, err := activateProgramInternal(statedb, address, codeHash, wasm, pagelimit, program.version, debugMode, burner) + info, asm, module, err := activateProgramInternal(statedb, address, codeHash, wasm, pagelimit, program.version, debugMode, &unlimitedGas) if err != nil { return nil, err From 393d1d01db82bbbc660b34a222d9c73a18dd51a4 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Thu, 9 May 2024 19:32:56 -0600 Subject: [PATCH 05/15] test wasm split --- system_tests/common_test.go | 4 +- system_tests/program_test.go | 78 ++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/system_tests/common_test.go b/system_tests/common_test.go index a9f655ff77..9d461bd48c 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -772,7 +772,7 @@ func createL2BlockChainWithStackConfig( stack, err = node.New(stackConfig) Require(t, err) - chainDb, err := stack.OpenDatabase("l2chaindata", 0, 0, "l2chaindata/", false) + chainDb, err := stack.OpenDatabaseWithFreezerAndWasm("l2chaindata", "wasm", 0, 0, "ancient", "l2chaindata/", false) Require(t, err) arbDb, err := stack.OpenDatabase("arbitrumdata", 0, 0, "arbitrumdata/", false) Require(t, err) @@ -976,7 +976,7 @@ func Create2ndNodeWithConfig( l2stack, err := node.New(stackConfig) Require(t, err) - l2chainDb, err := l2stack.OpenDatabase("l2chaindata", 0, 0, "l2chaindata/", false) + l2chainDb, err := l2stack.OpenDatabaseWithFreezerAndWasm("l2chaindata", "wasm", 0, 0, "", "l2chaindata/", false) Require(t, err) l2arbDb, err := l2stack.OpenDatabase("arbitrumdata", 0, 0, "arbitrumdata/", false) Require(t, err) diff --git a/system_tests/program_test.go b/system_tests/program_test.go index b20efe0740..079b6c0818 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -1458,3 +1458,81 @@ func formatTime(duration time.Duration) string { } return fmt.Sprintf("%.2f%s", span, units[unit]) } + +func TestWasmRecreate(t *testing.T) { + builder, auth, cleanup := setupProgramTest(t, true) + ctx := builder.ctx + l2info := builder.L2Info + l2client := builder.L2.Client + defer cleanup() + + storage := deployWasm(t, ctx, auth, l2client, rustFile("storage")) + + zero := common.Hash{} + val := common.HexToHash("0x121233445566") + + // do an onchain call - store value + storeTx := l2info.PrepareTxTo("Owner", &storage, l2info.TransferGas, nil, argsForStorageWrite(zero, val)) + Require(t, l2client.SendTransaction(ctx, storeTx)) + _, err := EnsureTxSucceeded(ctx, l2client, storeTx) + Require(t, err) + + testDir := t.TempDir() + nodeBStack := createStackConfigForTest(testDir) + nodeB, cleanupB := builder.Build2ndNode(t, &SecondNodeParams{stackConfig: nodeBStack}) + + _, err = EnsureTxSucceeded(ctx, nodeB.Client, storeTx) + Require(t, err) + + // make sure reading 2nd value succeeds from 2nd node + loadTx := l2info.PrepareTxTo("Owner", &storage, l2info.TransferGas, nil, argsForStorageRead(zero)) + result, err := arbutil.SendTxAsCall(ctx, nodeB.Client, loadTx, l2info.GetAddress("Owner"), nil, true) + Require(t, err) + if common.BytesToHash(result) != val { + Fatal(t, "got wrong value") + } + // close nodeB + cleanupB() + + // delete wasm dir of nodeB + + wasmPath := filepath.Join(testDir, "system_tests.test", "wasm") + dirContents, err := os.ReadDir(wasmPath) + Require(t, err) + if len(dirContents) == 0 { + Fatal(t, "not contents found before delete") + } + os.RemoveAll(wasmPath) + + // recreate nodeB - using same source dir (wasm deleted) + nodeB, cleanupB = builder.Build2ndNode(t, &SecondNodeParams{stackConfig: nodeBStack}) + + // test nodeB - sees existing transaction + _, err = EnsureTxSucceeded(ctx, nodeB.Client, storeTx) + Require(t, err) + + // test nodeB - answers eth_call (requires reloading wasm) + result, err = arbutil.SendTxAsCall(ctx, nodeB.Client, loadTx, l2info.GetAddress("Owner"), nil, true) + Require(t, err) + if common.BytesToHash(result) != val { + Fatal(t, "got wrong value") + } + + // send new tx (requires wasm) and check nodeB sees it as well + Require(t, l2client.SendTransaction(ctx, loadTx)) + + _, err = EnsureTxSucceeded(ctx, l2client, loadTx) + Require(t, err) + + _, err = EnsureTxSucceeded(ctx, nodeB.Client, loadTx) + Require(t, err) + + cleanupB() + dirContents, err = os.ReadDir(wasmPath) + Require(t, err) + if len(dirContents) == 0 { + Fatal(t, "not contents found before delete") + } + os.RemoveAll(wasmPath) + +} From d56f862d7a9038048c335caa502dbb5d12422805 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Thu, 9 May 2024 19:45:47 -0600 Subject: [PATCH 06/15] wasm split: fix wasm mplementation --- arbos/programs/wasm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arbos/programs/wasm.go b/arbos/programs/wasm.go index 105516dc62..8a67babc16 100644 --- a/arbos/programs/wasm.go +++ b/arbos/programs/wasm.go @@ -128,7 +128,7 @@ func startProgram(module uint32) uint32 //go:wasmimport programs send_response func sendResponse(req_id uint32) uint32 -func getLocalAsm(statedb vm.StateDB, moduleHash common.Hash, address common.Address, pagelimit uint16, debugMode bool, program Program) ([]byte, error) { +func getLocalAsm(statedb vm.StateDB, moduleHash common.Hash, address common.Address, pagelimit uint16, time uint64, debugMode bool, program Program) ([]byte, error) { return nil, nil } From 3ab3acffc33747955ece2ec6fb721b507001fbea Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 10 May 2024 08:47:24 -0600 Subject: [PATCH 07/15] wasm split: getLocalAsm fixes --- arbos/programs/native.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arbos/programs/native.go b/arbos/programs/native.go index b657472371..e1b464b39f 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -119,7 +119,7 @@ func activateProgramInternal( func getLocalAsm(statedb vm.StateDB, moduleHash common.Hash, address common.Address, pagelimit uint16, time uint64, debugMode bool, program Program) ([]byte, error) { localAsm, err := statedb.TryGetActivatedAsm(moduleHash) - if err == nil || len(localAsm) > 0 { + if err == nil && len(localAsm) > 0 { return localAsm, nil } @@ -127,19 +127,21 @@ func getLocalAsm(statedb vm.StateDB, moduleHash common.Hash, address common.Addr wasm, err := getWasm(statedb, address) if err != nil { - return nil, err + log.Error("Failed to reactivate program: getWasm", "address", address, "expected moduleHash", moduleHash, "err", err) + return nil, fmt.Errorf("failed to reactivate program address: %v err: %w", address, err) } unlimitedGas := uint64(0xffffffffffff) // we know program is activated, so it must be in correct version and not use too much memory info, asm, module, err := activateProgramInternal(statedb, address, codeHash, wasm, pagelimit, program.version, debugMode, &unlimitedGas) - if err != nil { - return nil, err + log.Error("failed to reactivate program", "address", address, "expected moduleHash", moduleHash, "err", err) + return nil, fmt.Errorf("failed to reactivate program address: %v err: %w", address, err) } if info.moduleHash != moduleHash { - return nil, errors.New("failed to re-activate program not found in database") + log.Error("failed to reactivate program", "address", address, "expected moduleHash", moduleHash, "got", info.moduleHash) + return nil, fmt.Errorf("failed to reactivate program. address: %v, expected ModuleHash: %v", address, moduleHash) } currentHoursSince := hoursSinceArbitrum(time) From 8326613d0a2365b52fe96d23b450df8a20237505 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 10 May 2024 10:33:07 -0600 Subject: [PATCH 08/15] wrap l2chaindata with wasm --- cmd/nitro/init.go | 20 +++++++++++++++----- system_tests/common_test.go | 11 +++++++++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/cmd/nitro/init.go b/cmd/nitro/init.go index 750bf03516..e9d6a5d3fa 100644 --- a/cmd/nitro/init.go +++ b/cmd/nitro/init.go @@ -172,16 +172,21 @@ func validateBlockChain(blockChain *core.BlockChain, chainConfig *params.ChainCo func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeConfig, chainId *big.Int, cacheConfig *core.CacheConfig, l1Client arbutil.L1Interface, rollupAddrs chaininfo.RollupAddresses) (ethdb.Database, *core.BlockChain, error) { if !config.Init.Force { - if readOnlyDb, err := stack.OpenDatabaseWithFreezerAndWasm("l2chaindata", "wasm", 0, 0, "", "l2chaindata/", true); err == nil { + if readOnlyDb, err := stack.OpenDatabaseWithFreezer("l2chaindata", 0, 0, "", "l2chaindata/", true); err == nil { if chainConfig := gethexec.TryReadStoredChainConfig(readOnlyDb); chainConfig != nil { readOnlyDb.Close() if !arbmath.BigEquals(chainConfig.ChainID, chainId) { return nil, nil, fmt.Errorf("database has chain ID %v but config has chain ID %v (are you sure this database is for the right chain?)", chainConfig.ChainID, chainId) } - chainDb, err := stack.OpenDatabaseWithFreezerAndWasm("l2chaindata", "wasm", config.Execution.Caching.DatabaseCache, config.Persistent.Handles, config.Persistent.Ancient, "l2chaindata/", false) + chainData, err := stack.OpenDatabaseWithFreezer("l2chaindata", config.Execution.Caching.DatabaseCache, config.Persistent.Handles, config.Persistent.Ancient, "l2chaindata/", false) if err != nil { - return chainDb, nil, err + return nil, nil, err + } + wasmDb, err := stack.OpenDatabase("wasm", config.Execution.Caching.DatabaseCache, config.Persistent.Handles, "wasm/", false) + if err != nil { + return nil, nil, err } + chainDb := stack.WrapDatabaseWithWasm(chainData, wasmDb) err = pruning.PruneChainDb(ctx, chainDb, stack, &config.Init, cacheConfig, l1Client, rollupAddrs, config.Node.ValidatorRequired()) if err != nil { return chainDb, nil, fmt.Errorf("error pruning: %w", err) @@ -230,10 +235,15 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo var initDataReader statetransfer.InitDataReader = nil - chainDb, err := stack.OpenDatabaseWithFreezerAndWasm("l2chaindata", "wasm", config.Execution.Caching.DatabaseCache, config.Persistent.Handles, config.Persistent.Ancient, "l2chaindata/", false) + chainData, err := stack.OpenDatabaseWithFreezer("l2chaindata", config.Execution.Caching.DatabaseCache, config.Persistent.Handles, config.Persistent.Ancient, "l2chaindata/", false) if err != nil { - return chainDb, nil, err + return nil, nil, err + } + wasmDb, err := stack.OpenDatabase("wasm", config.Execution.Caching.DatabaseCache, config.Persistent.Handles, "wasm/", false) + if err != nil { + return nil, nil, err } + chainDb := stack.WrapDatabaseWithWasm(chainData, wasmDb) if config.Init.ImportFile != "" { initDataReader, err = statetransfer.NewJsonInitDataReader(config.Init.ImportFile) diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 9d461bd48c..0ffe3990c3 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -772,8 +772,11 @@ func createL2BlockChainWithStackConfig( stack, err = node.New(stackConfig) Require(t, err) - chainDb, err := stack.OpenDatabaseWithFreezerAndWasm("l2chaindata", "wasm", 0, 0, "ancient", "l2chaindata/", false) + chainData, err := stack.OpenDatabase("l2chaindata", 0, 0, "l2chaindata/", false) Require(t, err) + wasmData, err := stack.OpenDatabase("wasm", 0, 0, "wasm/", false) + Require(t, err) + chainDb := stack.WrapDatabaseWithWasm(chainData, wasmData) arbDb, err := stack.OpenDatabase("arbitrumdata", 0, 0, "arbitrumdata/", false) Require(t, err) @@ -976,8 +979,12 @@ func Create2ndNodeWithConfig( l2stack, err := node.New(stackConfig) Require(t, err) - l2chainDb, err := l2stack.OpenDatabaseWithFreezerAndWasm("l2chaindata", "wasm", 0, 0, "", "l2chaindata/", false) + l2chainData, err := l2stack.OpenDatabase("l2chaindata", 0, 0, "l2chaindata/", false) + Require(t, err) + wasmData, err := l2stack.OpenDatabase("wasm", 0, 0, "wasm/", false) Require(t, err) + l2chainDb := l2stack.WrapDatabaseWithWasm(l2chainData, wasmData) + l2arbDb, err := l2stack.OpenDatabase("arbitrumdata", 0, 0, "arbitrumdata/", false) Require(t, err) initReader := statetransfer.NewMemoryInitDataReader(l2InitData) From cfd24dcdd83b00610d107fe77234c08247a58ba0 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 10 May 2024 10:33:50 -0600 Subject: [PATCH 09/15] geth: update pin --- go-ethereum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go-ethereum b/go-ethereum index 37b6489382..45145108b1 160000 --- a/go-ethereum +++ b/go-ethereum @@ -1 +1 @@ -Subproject commit 37b6489382bb884dd1216dcb0f6a224ce2ca5fe2 +Subproject commit 45145108b11e39ea57ee5b0a1238440edd1fa3ab From 1e153dd9c0b5171f058984c696a1f9ce26f8f8ad Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 10 May 2024 11:53:53 -0600 Subject: [PATCH 10/15] program: compilation fix --- arbos/programs/native.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 4a3b8992cf..1111dc7233 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -176,7 +176,7 @@ func callProgram( db := interpreter.Evm().StateDB debug := stylusParams.debugMode - if len(asm) == 0 { + if len(localAsm) == 0 { log.Error("missing asm", "program", address, "module", moduleHash) panic("missing asm") } From 566e72cfdd42c9111bf43ac0d9c424f41c27c087 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 10 May 2024 15:23:50 -0600 Subject: [PATCH 11/15] cache program could also recalc asm --- arbos/programs/native.go | 12 ++++++++---- arbos/programs/programs.go | 10 +++++++--- arbos/programs/wasm.go | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/arbos/programs/native.go b/arbos/programs/native.go index 1111dc7233..18f6e8e48d 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -221,11 +221,15 @@ func handleReqImpl(apiId usize, req_type u32, data *rustSlice, costPtr *u64, out // Caches a program in Rust. We write a record so that we can undo on revert. // For gas estimation and eth_call, we ignore permanent updates and rely on Rust's LRU. -func cacheProgram(db vm.StateDB, module common.Hash, version uint16, debug bool, runMode core.MessageRunMode) { +func cacheProgram(db vm.StateDB, module common.Hash, program Program, params *StylusParams, debug bool, time uint64, runMode core.MessageRunMode) { if runMode == core.MessageCommitMode { - asm := db.GetActivatedAsm(module) - state.CacheWasmRust(asm, module, version, debug) - db.RecordCacheWasm(state.CacheWasm{ModuleHash: module, Version: version, Debug: debug}) + // address is only used for logging + asm, err := getLocalAsm(db, module, common.Address{}, params.PageLimit, time, debug, program) + if err != nil { + panic("unable to recreate wasm") + } + state.CacheWasmRust(asm, module, program.version, debug) + db.RecordCacheWasm(state.CacheWasm{ModuleHash: module, Version: program.version, Debug: debug}) } } diff --git a/arbos/programs/programs.go b/arbos/programs/programs.go index b277f5d678..8395980f68 100644 --- a/arbos/programs/programs.go +++ b/arbos/programs/programs.go @@ -120,14 +120,13 @@ func (p Programs) ActivateProgram(evm *vm.EVM, address common.Address, runMode c return 0, codeHash, common.Hash{}, nil, true, err } - // replace the cached asm + // remove prev asm if cached { oldModuleHash, err := p.moduleHashes.Get(codeHash) if err != nil { return 0, codeHash, common.Hash{}, nil, true, err } evictProgram(statedb, oldModuleHash, currentVersion, debugMode, runMode, expired) - cacheProgram(statedb, info.moduleHash, stylusVersion, debugMode, runMode) } if err := p.moduleHashes.Set(codeHash, info.moduleHash); err != nil { return 0, codeHash, common.Hash{}, nil, true, err @@ -152,6 +151,11 @@ func (p Programs) ActivateProgram(evm *vm.EVM, address common.Address, runMode c activatedAt: hoursSinceArbitrum(time), cached: cached, } + // replace the cached asm + if cached { + cacheProgram(statedb, info.moduleHash, programData, params, debugMode, time, runMode) + } + return stylusVersion, codeHash, info.moduleHash, dataFee, false, p.setProgram(codeHash, programData) } @@ -386,7 +390,7 @@ func (p Programs) SetProgramCached( return err } if cache { - cacheProgram(db, moduleHash, program.version, debug, runMode) + cacheProgram(db, moduleHash, program, params, debug, time, runMode) } else { evictProgram(db, moduleHash, program.version, debug, runMode, expired) } diff --git a/arbos/programs/wasm.go b/arbos/programs/wasm.go index 8a67babc16..ee8da44934 100644 --- a/arbos/programs/wasm.go +++ b/arbos/programs/wasm.go @@ -95,7 +95,7 @@ func activateProgram( } // stub any non-consensus, Rust-side caching updates -func cacheProgram(db vm.StateDB, module common.Hash, version uint16, debug bool, mode core.MessageRunMode) { +func cacheProgram(db vm.StateDB, module common.Hash, program Program, params *StylusParams, debug bool, time uint64, runMode core.MessageRunMode) { } func evictProgram(db vm.StateDB, module common.Hash, version uint16, debug bool, mode core.MessageRunMode, forever bool) { } From 97db9c98fe5d72ba7064310c4ccfa2191cc082be Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 10 May 2024 15:24:35 -0600 Subject: [PATCH 12/15] geth: update pin for TryGetActivated --- go-ethereum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go-ethereum b/go-ethereum index 5ac25eda5d..8d94d2b164 160000 --- a/go-ethereum +++ b/go-ethereum @@ -1 +1 @@ -Subproject commit 5ac25eda5df447c061e33d74a6a85b03f0a7d85d +Subproject commit 8d94d2b164ea3b277a1e87dcdc6f61c5beeaefd8 From de022e8655ada2eaa6ab2f50b12e728ade4ecdb3 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 10 May 2024 16:20:02 -0600 Subject: [PATCH 13/15] dbWithWasm moved --- cmd/nitro/init.go | 4 ++-- system_tests/common_test.go | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/nitro/init.go b/cmd/nitro/init.go index e9d6a5d3fa..c52c87732c 100644 --- a/cmd/nitro/init.go +++ b/cmd/nitro/init.go @@ -186,7 +186,7 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo if err != nil { return nil, nil, err } - chainDb := stack.WrapDatabaseWithWasm(chainData, wasmDb) + chainDb := rawdb.WrapDatabaseWithWasm(chainData, wasmDb) err = pruning.PruneChainDb(ctx, chainDb, stack, &config.Init, cacheConfig, l1Client, rollupAddrs, config.Node.ValidatorRequired()) if err != nil { return chainDb, nil, fmt.Errorf("error pruning: %w", err) @@ -243,7 +243,7 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo if err != nil { return nil, nil, err } - chainDb := stack.WrapDatabaseWithWasm(chainData, wasmDb) + chainDb := rawdb.WrapDatabaseWithWasm(chainData, wasmDb) if config.Init.ImportFile != "" { initDataReader, err = statetransfer.NewJsonInitDataReader(config.Init.ImportFile) diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 3e5f6fd228..f6bfde2108 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -44,6 +44,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -776,7 +777,7 @@ func createL2BlockChainWithStackConfig( Require(t, err) wasmData, err := stack.OpenDatabase("wasm", 0, 0, "wasm/", false) Require(t, err) - chainDb := stack.WrapDatabaseWithWasm(chainData, wasmData) + chainDb := rawdb.WrapDatabaseWithWasm(chainData, wasmData) arbDb, err := stack.OpenDatabase("arbitrumdata", 0, 0, "arbitrumdata/", false) Require(t, err) @@ -983,7 +984,7 @@ func Create2ndNodeWithConfig( Require(t, err) wasmData, err := l2stack.OpenDatabase("wasm", 0, 0, "wasm/", false) Require(t, err) - l2chainDb := l2stack.WrapDatabaseWithWasm(l2chainData, wasmData) + l2chainDb := rawdb.WrapDatabaseWithWasm(l2chainData, wasmData) l2arbDb, err := l2stack.OpenDatabase("arbitrumdata", 0, 0, "arbitrumdata/", false) Require(t, err) From 90697dcab330c509ae3505a5597bb40d06cf9ce4 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 10 May 2024 16:20:26 -0600 Subject: [PATCH 14/15] geth: update pin, move dbWithWasm --- go-ethereum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go-ethereum b/go-ethereum index 8d94d2b164..f8917436fc 160000 --- a/go-ethereum +++ b/go-ethereum @@ -1 +1 @@ -Subproject commit 8d94d2b164ea3b277a1e87dcdc6f61c5beeaefd8 +Subproject commit f8917436fcfa6a6a2b15c0ec7e6f318687491a8c From 952d2253065590dbf846af103360e87c4eacc3e3 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Tue, 14 May 2024 19:11:19 -0600 Subject: [PATCH 15/15] geth: update pin --- go-ethereum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go-ethereum b/go-ethereum index f8917436fc..8048ac4bed 160000 --- a/go-ethereum +++ b/go-ethereum @@ -1 +1 @@ -Subproject commit f8917436fcfa6a6a2b15c0ec7e6f318687491a8c +Subproject commit 8048ac4bed2eda18284e3c022ea5ee4cce771134