diff --git a/cmd/aida-sdb/record.go b/cmd/aida-sdb/record.go index 331fba50c..437a51927 100644 --- a/cmd/aida-sdb/record.go +++ b/cmd/aida-sdb/record.go @@ -7,6 +7,7 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension/tracker" "github.com/Fantom-foundation/Aida/executor/extension/validator" "github.com/Fantom-foundation/Aida/logger" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/urfave/cli/v2" @@ -58,16 +59,16 @@ func RecordStateDbTrace(ctx *cli.Context) error { func record( cfg *utils.Config, - provider executor.Provider[*substate.Substate], - processor executor.Processor[*substate.Substate], - extra []executor.Extension[*substate.Substate], + provider executor.Provider[txcontext.TxContext], + processor executor.Processor[txcontext.TxContext], + extra []executor.Extension[txcontext.TxContext], ) error { - var extensions = []executor.Extension[*substate.Substate]{ - profiler.MakeCpuProfiler[*substate.Substate](cfg), - tracker.MakeProgressLogger[*substate.Substate](cfg, 0), + var extensions = []executor.Extension[txcontext.TxContext]{ + profiler.MakeCpuProfiler[txcontext.TxContext](cfg), + tracker.MakeProgressLogger[txcontext.TxContext](cfg, 0), tracker.MakeProgressTracker(cfg, 0), statedb.MakeTemporaryStatePrepper(cfg), - statedb.MakeProxyRecorderPrepper(cfg), + statedb.MakeProxyRecorderPrepper[txcontext.TxContext](cfg), validator.MakeLiveDbValidator(cfg), } diff --git a/cmd/aida-sdb/record_test.go b/cmd/aida-sdb/record_test.go index cef225928..5080d1d05 100644 --- a/cmd/aida-sdb/record_test.go +++ b/cmd/aida-sdb/record_test.go @@ -5,6 +5,8 @@ import ( "testing" "github.com/Fantom-foundation/Aida/executor" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" @@ -15,9 +17,9 @@ var testingAddress = common.Address{1} func TestSdbRecord_AllDbEventsAreIssuedInOrder(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) - processor := executor.NewMockProcessor[*substate.Substate](ctrl) - ext := executor.NewMockExtension[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) + processor := executor.NewMockProcessor[txcontext.TxContext](ctrl) + ext := executor.NewMockExtension[txcontext.TxContext](ctrl) path := t.TempDir() + "test_trace" cfg := &utils.Config{ First: 10, @@ -30,40 +32,40 @@ func TestSdbRecord_AllDbEventsAreIssuedInOrder(t *testing.T) { provider.EXPECT(). Run(10, 12, gomock.Any()). - DoAndReturn(func(from int, to int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(from int, to int, consumer executor.Consumer[txcontext.TxContext]) error { for i := from; i < to; i++ { - consumer(executor.TransactionInfo[*substate.Substate]{Block: i, Transaction: 3, Data: emptyTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: i, Transaction: utils.PseudoTx, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: i, Transaction: 3, Data: substatecontext.NewTxContext(emptyTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: i, Transaction: utils.PseudoTx, Data: substatecontext.NewTxContext(emptyTx)}) } return nil }) // All transactions are processed in order gomock.InOrder( - ext.EXPECT().PreRun(executor.AtBlock[*substate.Substate](10), gomock.Any()), + ext.EXPECT().PreRun(executor.AtBlock[txcontext.TxContext](10), gomock.Any()), // block 10 - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](10, 3), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](10, 3), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](10, 3), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](10, 3), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](10, 3), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](10, 3), gomock.Any()), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](10, utils.PseudoTx), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](10, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](10, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](10, utils.PseudoTx), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](10, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](10, utils.PseudoTx), gomock.Any()), // block 11 - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](11, 3), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](11, 3), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](11, 3), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](11, 3), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](11, 3), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](11, 3), gomock.Any()), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](11, utils.PseudoTx), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](11, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](11, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](11, utils.PseudoTx), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](11, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](11, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostRun(executor.AtBlock[*substate.Substate](12), gomock.Any(), nil), + ext.EXPECT().PostRun(executor.AtBlock[txcontext.TxContext](12), gomock.Any(), nil), ) - if err := record(cfg, provider, processor, []executor.Extension[*substate.Substate]{ext}); err != nil { + if err := record(cfg, provider, processor, []executor.Extension[txcontext.TxContext]{ext}); err != nil { t.Errorf("record failed: %v", err) } } diff --git a/cmd/aida-sdb/trace/replay_substate.go b/cmd/aida-sdb/trace/replay_substate.go index ad2814813..2ff77149f 100644 --- a/cmd/aida-sdb/trace/replay_substate.go +++ b/cmd/aida-sdb/trace/replay_substate.go @@ -10,8 +10,8 @@ import ( "github.com/Fantom-foundation/Aida/state" "github.com/Fantom-foundation/Aida/tracer/context" "github.com/Fantom-foundation/Aida/tracer/operation" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" "github.com/urfave/cli/v2" ) @@ -37,8 +37,8 @@ func ReplaySubstate(ctx *cli.Context) error { processor := makeSubstateProcessor(cfg, rCtx, operationProvider) - var extra = []executor.Extension[*substate.Substate]{ - profiler.MakeReplayProfiler[*substate.Substate](cfg, rCtx), + var extra = []executor.Extension[txcontext.TxContext]{ + profiler.MakeReplayProfiler[txcontext.TxContext](cfg, rCtx), } return replaySubstate(cfg, substateProvider, processor, nil, extra) @@ -56,7 +56,7 @@ type substateProcessor struct { operationProvider executor.Provider[[]operation.Operation] } -func (p substateProcessor) Process(state executor.State[*substate.Substate], ctx *executor.Context) error { +func (p substateProcessor) Process(state executor.State[txcontext.TxContext], ctx *executor.Context) error { return p.operationProvider.Run(state.Block, state.Block, func(t executor.TransactionInfo[[]operation.Operation]) error { p.runTransaction(uint64(state.Block), t.Data, ctx.State) return nil @@ -65,21 +65,21 @@ func (p substateProcessor) Process(state executor.State[*substate.Substate], ctx func replaySubstate( cfg *utils.Config, - provider executor.Provider[*substate.Substate], - processor executor.Processor[*substate.Substate], + provider executor.Provider[txcontext.TxContext], + processor executor.Processor[txcontext.TxContext], stateDb state.StateDB, - extra []executor.Extension[*substate.Substate], + extra []executor.Extension[txcontext.TxContext], ) error { - var extensionList = []executor.Extension[*substate.Substate]{ - profiler.MakeCpuProfiler[*substate.Substate](cfg), - tracker.MakeProgressLogger[*substate.Substate](cfg, 0), - profiler.MakeMemoryUsagePrinter[*substate.Substate](cfg), - profiler.MakeMemoryProfiler[*substate.Substate](cfg), + var extensionList = []executor.Extension[txcontext.TxContext]{ + profiler.MakeCpuProfiler[txcontext.TxContext](cfg), + tracker.MakeProgressLogger[txcontext.TxContext](cfg, 0), + profiler.MakeMemoryUsagePrinter[txcontext.TxContext](cfg), + profiler.MakeMemoryProfiler[txcontext.TxContext](cfg), validator.MakeLiveDbValidator(cfg), } if stateDb == nil { - extensionList = append(extensionList, statedb.MakeStateDbManager[*substate.Substate](cfg)) + extensionList = append(extensionList, statedb.MakeStateDbManager[txcontext.TxContext](cfg)) } if cfg.DbImpl == "memory" { diff --git a/cmd/aida-sdb/trace/replay_substate_test.go b/cmd/aida-sdb/trace/replay_substate_test.go index 5410d17aa..1cfbc5b7b 100644 --- a/cmd/aida-sdb/trace/replay_substate_test.go +++ b/cmd/aida-sdb/trace/replay_substate_test.go @@ -8,6 +8,8 @@ import ( "github.com/Fantom-foundation/Aida/state" "github.com/Fantom-foundation/Aida/tracer/context" "github.com/Fantom-foundation/Aida/tracer/operation" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" @@ -18,9 +20,9 @@ var testingAddress = common.Address{1} func TestSdbReplaySubstate_AllDbEventsAreIssuedInOrder(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) - processor := executor.NewMockProcessor[*substate.Substate](ctrl) - ext := executor.NewMockExtension[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) + processor := executor.NewMockProcessor[txcontext.TxContext](ctrl) + ext := executor.NewMockExtension[txcontext.TxContext](ctrl) cfg := &utils.Config{} cfg.DbImpl = "carmen" @@ -31,39 +33,39 @@ func TestSdbReplaySubstate_AllDbEventsAreIssuedInOrder(t *testing.T) { provider.EXPECT(). Run(0, 1, gomock.Any()). - DoAndReturn(func(from int, to int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(from int, to int, consumer executor.Consumer[txcontext.TxContext]) error { for i := from; i < to; i++ { - consumer(executor.TransactionInfo[*substate.Substate]{Block: 0, Transaction: 0, Data: testTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: 0, Transaction: 1, Data: testTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 0, Transaction: 0, Data: substatecontext.NewTxContext(testTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 0, Transaction: 1, Data: substatecontext.NewTxContext(testTx)}) } return nil }) // All transactions are processed in order gomock.InOrder( - ext.EXPECT().PreRun(executor.AtBlock[*substate.Substate](0), gomock.Any()), + ext.EXPECT().PreRun(executor.AtBlock[txcontext.TxContext](0), gomock.Any()), // tx 0 - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](0, 0), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](0, 0), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](0, 0), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](0, 0), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](0, 0), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](0, 0), gomock.Any()), // tx 1 - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](0, 1), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](0, 1), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](0, 1), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](0, 1), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](0, 1), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](0, 1), gomock.Any()), - ext.EXPECT().PostRun(executor.AtBlock[*substate.Substate](1), gomock.Any(), nil), + ext.EXPECT().PostRun(executor.AtBlock[txcontext.TxContext](1), gomock.Any(), nil), ) - if err := replaySubstate(cfg, provider, processor, nil, []executor.Extension[*substate.Substate]{ext}); err != nil { + if err := replaySubstate(cfg, provider, processor, nil, []executor.Extension[txcontext.TxContext]{ext}); err != nil { t.Errorf("record failed: %v", err) } } func TestSdbReplaySubstate_StateDbPrepperIsAddedIfDbImplIsMemory(t *testing.T) { ctrl := gomock.NewController(t) - substateProvider := executor.NewMockProvider[*substate.Substate](ctrl) + substateProvider := executor.NewMockProvider[txcontext.TxContext](ctrl) operationProvider := executor.NewMockProvider[[]operation.Operation](ctrl) db := state.NewMockStateDB(ctrl) @@ -76,9 +78,9 @@ func TestSdbReplaySubstate_StateDbPrepperIsAddedIfDbImplIsMemory(t *testing.T) { substateProvider.EXPECT(). Run(0, 1, gomock.Any()). - DoAndReturn(func(from int, to int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(from int, to int, consumer executor.Consumer[txcontext.TxContext]) error { for i := from; i < to; i++ { - consumer(executor.TransactionInfo[*substate.Substate]{Block: 0, Transaction: 0, Data: testTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 0, Transaction: 0, Data: substatecontext.NewTxContext(testTx)}) } return nil }) @@ -103,7 +105,7 @@ func TestSdbReplaySubstate_StateDbPrepperIsAddedIfDbImplIsMemory(t *testing.T) { func TestSdbReplaySubstate_TxPrimerIsAddedIfDbImplIsNotMemory(t *testing.T) { ctrl := gomock.NewController(t) - substateProvider := executor.NewMockProvider[*substate.Substate](ctrl) + substateProvider := executor.NewMockProvider[txcontext.TxContext](ctrl) operationProvider := executor.NewMockProvider[[]operation.Operation](ctrl) db := state.NewMockStateDB(ctrl) bulkLoad := state.NewMockBulkLoad(ctrl) @@ -117,9 +119,9 @@ func TestSdbReplaySubstate_TxPrimerIsAddedIfDbImplIsNotMemory(t *testing.T) { substateProvider.EXPECT(). Run(1, 2, gomock.Any()). - DoAndReturn(func(from int, to int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(from int, to int, consumer executor.Consumer[txcontext.TxContext]) error { for i := from; i < to; i++ { - consumer(executor.TransactionInfo[*substate.Substate]{Block: 1, Transaction: 0, Data: testTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 1, Transaction: 0, Data: substatecontext.NewTxContext(testTx)}) } return nil }) diff --git a/cmd/aida-stochastic-sdb/stochastic/record.go b/cmd/aida-stochastic-sdb/stochastic/record.go index 92c75d7fb..2b126d101 100644 --- a/cmd/aida-stochastic-sdb/stochastic/record.go +++ b/cmd/aida-stochastic-sdb/stochastic/record.go @@ -10,6 +10,7 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/state" "github.com/Fantom-foundation/Aida/stochastic" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/urfave/cli/v2" @@ -102,9 +103,9 @@ func stochasticRecordAction(ctx *cli.Context) error { } var statedb state.StateDB - statedb = state.MakeInMemoryStateDB(&tx.Substate.InputAlloc, tx.Block) + statedb = state.MakeInMemoryStateDB(substatecontext.NewWorldState(tx.Substate.InputAlloc), tx.Block) statedb = stochastic.NewEventProxy(statedb, &eventRegistry) - if err = processor.ProcessTransaction(statedb, int(tx.Block), tx.Transaction, tx.Substate); err != nil { + if err = processor.ProcessTransaction(statedb, int(tx.Block), tx.Transaction, substatecontext.NewTxContext(tx.Substate)); err != nil { return err } diff --git a/cmd/aida-vm-adb/run_vm_adb.go b/cmd/aida-vm-adb/run_vm_adb.go index 917623a61..6d9ede0c5 100644 --- a/cmd/aida-vm-adb/run_vm_adb.go +++ b/cmd/aida-vm-adb/run_vm_adb.go @@ -7,8 +7,8 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension/tracker" "github.com/Fantom-foundation/Aida/executor/extension/validator" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" "github.com/urfave/cli/v2" ) @@ -40,25 +40,25 @@ func RunVmAdb(ctx *cli.Context) error { func run( cfg *utils.Config, - provider executor.Provider[*substate.Substate], + provider executor.Provider[txcontext.TxContext], stateDb state.StateDB, - processor executor.Processor[*substate.Substate], - extra []executor.Extension[*substate.Substate], + processor executor.Processor[txcontext.TxContext], + extra []executor.Extension[txcontext.TxContext], ) error { - extensionList := []executor.Extension[*substate.Substate]{ - profiler.MakeCpuProfiler[*substate.Substate](cfg), - statedb.MakeArchivePrepper(), - tracker.MakeProgressLogger[*substate.Substate](cfg, 0), - tracker.MakeErrorLogger[*substate.Substate](cfg), + extensionList := []executor.Extension[txcontext.TxContext]{ + profiler.MakeCpuProfiler[txcontext.TxContext](cfg), + statedb.MakeArchivePrepper[txcontext.TxContext](), + tracker.MakeProgressLogger[txcontext.TxContext](cfg, 0), + tracker.MakeErrorLogger[txcontext.TxContext](cfg), validator.MakeArchiveDbValidator(cfg), } if stateDb == nil { extensionList = append( extensionList, - statedb.MakeStateDbManager[*substate.Substate](cfg), - statedb.MakeArchiveBlockChecker[*substate.Substate](cfg), - tracker.MakeDbLogger[*substate.Substate](cfg), + statedb.MakeStateDbManager[txcontext.TxContext](cfg), + statedb.MakeArchiveBlockChecker[txcontext.TxContext](cfg), + tracker.MakeDbLogger[txcontext.TxContext](cfg), ) } diff --git a/cmd/aida-vm-adb/run_vm_adb_test.go b/cmd/aida-vm-adb/run_vm_adb_test.go index 5cd276ae2..bab87c901 100644 --- a/cmd/aida-vm-adb/run_vm_adb_test.go +++ b/cmd/aida-vm-adb/run_vm_adb_test.go @@ -7,6 +7,8 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" @@ -17,7 +19,7 @@ var testingAddress = common.Address{1} func TestVmAdb_AllDbEventsAreIssuedInOrder_Sequential(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) archiveBlockOne := state.NewMockNonCommittableStateDB(ctrl) archiveBlockTwo := state.NewMockNonCommittableStateDB(ctrl) @@ -36,14 +38,14 @@ func TestVmAdb_AllDbEventsAreIssuedInOrder_Sequential(t *testing.T) { // Simulate the execution of three transactions in two blocks. provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { // Block 2 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: emptyTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 2, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 2, Data: substatecontext.NewTxContext(emptyTx)}) // Block 3 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 3, Transaction: 1, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 3, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) // Block 4 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 4, Transaction: utils.PseudoTx, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 4, Transaction: utils.PseudoTx, Data: substatecontext.NewTxContext(emptyTx)}) return nil }) @@ -101,7 +103,7 @@ func TestVmAdb_AllDbEventsAreIssuedInOrder_Sequential(t *testing.T) { func TestVmAdb_AllDbEventsAreIssuedInOrder_Parallel(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) archiveBlockOne := state.NewMockNonCommittableStateDB(ctrl) archiveBlockTwo := state.NewMockNonCommittableStateDB(ctrl) @@ -120,14 +122,14 @@ func TestVmAdb_AllDbEventsAreIssuedInOrder_Parallel(t *testing.T) { // Simulate the execution of three transactions in two blocks. provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { // Block 2 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: emptyTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 2, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 2, Data: substatecontext.NewTxContext(emptyTx)}) // Block 3 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 3, Transaction: 1, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 3, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) // Block 4 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 4, Transaction: utils.PseudoTx, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 4, Transaction: utils.PseudoTx, Data: substatecontext.NewTxContext(emptyTx)}) return nil }) @@ -193,11 +195,11 @@ func TestVmAdb_AllDbEventsAreIssuedInOrder_Parallel(t *testing.T) { func TestVmAdb_AllTransactionsAreProcessedInOrder_Sequential(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) archive := state.NewMockNonCommittableStateDB(ctrl) - ext := executor.NewMockExtension[*substate.Substate](ctrl) - processor := executor.NewMockProcessor[*substate.Substate](ctrl) + ext := executor.NewMockExtension[txcontext.TxContext](ctrl) + processor := executor.NewMockProcessor[txcontext.TxContext](ctrl) config := &utils.Config{ First: 2, @@ -210,14 +212,14 @@ func TestVmAdb_AllTransactionsAreProcessedInOrder_Sequential(t *testing.T) { // Simulate the execution of three transactions in two blocks. provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { // Block 2 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: emptyTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 2, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 2, Data: substatecontext.NewTxContext(emptyTx)}) // Block 3 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 3, Transaction: 1, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 3, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) // Block 4 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 4, Transaction: utils.PseudoTx, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 4, Transaction: utils.PseudoTx, Data: substatecontext.NewTxContext(emptyTx)}) return nil }) @@ -227,55 +229,55 @@ func TestVmAdb_AllTransactionsAreProcessedInOrder_Sequential(t *testing.T) { // all blocks and transactions need to be in order. gomock.InOrder( - ext.EXPECT().PreRun(executor.AtBlock[*substate.Substate](2), gomock.Any()), + ext.EXPECT().PreRun(executor.AtBlock[txcontext.TxContext](2), gomock.Any()), // Block 2 // Tx 1 db.EXPECT().GetArchiveState(uint64(1)).Return(archive, nil), - ext.EXPECT().PreBlock(executor.AtBlock[*substate.Substate](2), gomock.Any()), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), + ext.EXPECT().PreBlock(executor.AtBlock[txcontext.TxContext](2), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), // Tx 2 - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), - ext.EXPECT().PostBlock(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), + ext.EXPECT().PostBlock(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), archive.EXPECT().Release(), // Block 3 db.EXPECT().GetArchiveState(uint64(2)).Return(archive, nil), - ext.EXPECT().PreBlock(executor.AtBlock[*substate.Substate](3), gomock.Any()), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), - ext.EXPECT().PostBlock(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), + ext.EXPECT().PreBlock(executor.AtBlock[txcontext.TxContext](3), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), + ext.EXPECT().PostBlock(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), archive.EXPECT().Release(), // Block 4 db.EXPECT().GetArchiveState(uint64(3)).Return(archive, nil), - ext.EXPECT().PreBlock(executor.AtBlock[*substate.Substate](4), gomock.Any()), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostBlock(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PreBlock(executor.AtBlock[txcontext.TxContext](4), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PostBlock(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), archive.EXPECT().Release(), - ext.EXPECT().PostRun(executor.AtBlock[*substate.Substate](5), gomock.Any(), nil), + ext.EXPECT().PostRun(executor.AtBlock[txcontext.TxContext](5), gomock.Any(), nil), ) - if err := run(config, provider, db, processor, []executor.Extension[*substate.Substate]{ext}); err != nil { + if err := run(config, provider, db, processor, []executor.Extension[txcontext.TxContext]{ext}); err != nil { t.Errorf("run failed: %v", err) } } func TestVmAdb_AllTransactionsAreProcessed_Parallel(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) archive := state.NewMockNonCommittableStateDB(ctrl) - ext := executor.NewMockExtension[*substate.Substate](ctrl) - processor := executor.NewMockProcessor[*substate.Substate](ctrl) + ext := executor.NewMockExtension[txcontext.TxContext](ctrl) + processor := executor.NewMockProcessor[txcontext.TxContext](ctrl) config := &utils.Config{ First: 2, @@ -288,14 +290,14 @@ func TestVmAdb_AllTransactionsAreProcessed_Parallel(t *testing.T) { // Simulate the execution of three transactions in two blocks. provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { // Block 2 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: emptyTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 2, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 2, Data: substatecontext.NewTxContext(emptyTx)}) // Block 3 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 3, Transaction: 1, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 3, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) // Block 4 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 4, Transaction: utils.PseudoTx, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 4, Transaction: utils.PseudoTx, Data: substatecontext.NewTxContext(emptyTx)}) return nil }) @@ -303,56 +305,56 @@ func TestVmAdb_AllTransactionsAreProcessed_Parallel(t *testing.T) { // are properly opened, prepared, executed, and closed. // Since we are running parallel mode with multiple workers block // order does not have to be preserved, only transaction order matters. - ext.EXPECT().PreRun(executor.AtBlock[*substate.Substate](2), gomock.Any()) + ext.EXPECT().PreRun(executor.AtBlock[txcontext.TxContext](2), gomock.Any()) // Block 2 gomock.InOrder( db.EXPECT().GetArchiveState(uint64(1)).Return(archive, nil), - ext.EXPECT().PreBlock(executor.AtBlock[*substate.Substate](2), gomock.Any()), + ext.EXPECT().PreBlock(executor.AtBlock[txcontext.TxContext](2), gomock.Any()), // Tx 1 - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), // Tx 2 - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), - ext.EXPECT().PostBlock(executor.AtBlock[*substate.Substate](2), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), + ext.EXPECT().PostBlock(executor.AtBlock[txcontext.TxContext](2), gomock.Any()), archive.EXPECT().Release(), ) // Block 3 gomock.InOrder( db.EXPECT().GetArchiveState(uint64(2)).Return(archive, nil), - ext.EXPECT().PreBlock(executor.AtBlock[*substate.Substate](3), gomock.Any()), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), - ext.EXPECT().PostBlock(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), + ext.EXPECT().PreBlock(executor.AtBlock[txcontext.TxContext](3), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), + ext.EXPECT().PostBlock(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), archive.EXPECT().Release(), ) // Block 4 gomock.InOrder( db.EXPECT().GetArchiveState(uint64(3)).Return(archive, nil), - ext.EXPECT().PreBlock(executor.AtBlock[*substate.Substate](4), gomock.Any()), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostBlock(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PreBlock(executor.AtBlock[txcontext.TxContext](4), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PostBlock(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), archive.EXPECT().Release(), ) - ext.EXPECT().PostRun(executor.AtBlock[*substate.Substate](5), gomock.Any(), nil) + ext.EXPECT().PostRun(executor.AtBlock[txcontext.TxContext](5), gomock.Any(), nil) - if err := run(config, provider, db, processor, []executor.Extension[*substate.Substate]{ext}); err != nil { + if err := run(config, provider, db, processor, []executor.Extension[txcontext.TxContext]{ext}); err != nil { t.Errorf("run failed: %v", err) } } func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Sequential(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) archive := state.NewMockNonCommittableStateDB(ctrl) @@ -367,8 +369,8 @@ func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Sequential(t *testing.T) provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { - return consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: testTx}) + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { + return consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(testTx)}) }) gomock.InOrder( @@ -404,7 +406,7 @@ func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Sequential(t *testing.T) func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Parallel(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) archive := state.NewMockNonCommittableStateDB(ctrl) cfg := &utils.Config{ @@ -418,8 +420,8 @@ func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Parallel(t *testing.T) { provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { - return consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: testTx}) + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { + return consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(testTx)}) }) gomock.InOrder( @@ -455,7 +457,7 @@ func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Parallel(t *testing.T) { func TestVmAdb_ValidationFailsOnInvalidTransaction_Sequential(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) archive := state.NewMockNonCommittableStateDB(ctrl) cfg := &utils.Config{ @@ -468,8 +470,8 @@ func TestVmAdb_ValidationFailsOnInvalidTransaction_Sequential(t *testing.T) { provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { - return consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: testTx}) + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { + return consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(testTx)}) }) gomock.InOrder( @@ -496,7 +498,7 @@ func TestVmAdb_ValidationFailsOnInvalidTransaction_Sequential(t *testing.T) { func TestVmAdb_ValidationFailsOnInvalidTransaction_Parallel(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) archive := state.NewMockNonCommittableStateDB(ctrl) cfg := &utils.Config{ @@ -510,8 +512,8 @@ func TestVmAdb_ValidationFailsOnInvalidTransaction_Parallel(t *testing.T) { provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { - return consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: testTx}) + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { + return consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(testTx)}) }) gomock.InOrder( diff --git a/cmd/aida-vm-sdb/run_substate.go b/cmd/aida-vm-sdb/run_substate.go index 56f714b65..546011156 100644 --- a/cmd/aida-vm-sdb/run_substate.go +++ b/cmd/aida-vm-sdb/run_substate.go @@ -12,8 +12,8 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension/tracker" "github.com/Fantom-foundation/Aida/executor/extension/validator" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" "github.com/urfave/cli/v2" ) @@ -37,49 +37,49 @@ func RunSubstate(ctx *cli.Context) error { func runSubstates( cfg *utils.Config, - provider executor.Provider[*substate.Substate], + provider executor.Provider[txcontext.TxContext], stateDb state.StateDB, - processor executor.Processor[*substate.Substate], - extra []executor.Extension[*substate.Substate], + processor executor.Processor[txcontext.TxContext], + extra []executor.Extension[txcontext.TxContext], ) error { // order of extensionList has to be maintained - var extensionList = []executor.Extension[*substate.Substate]{ - profiler.MakeCpuProfiler[*substate.Substate](cfg), - profiler.MakeDiagnosticServer[*substate.Substate](cfg), + var extensionList = []executor.Extension[txcontext.TxContext]{ + profiler.MakeCpuProfiler[txcontext.TxContext](cfg), + profiler.MakeDiagnosticServer[txcontext.TxContext](cfg), } if stateDb == nil { extensionList = append( extensionList, - statedb.MakeStateDbManager[*substate.Substate](cfg), - statedb.MakeLiveDbBlockChecker[*substate.Substate](cfg), - tracker.MakeDbLogger[*substate.Substate](cfg), + statedb.MakeStateDbManager[txcontext.TxContext](cfg), + statedb.MakeLiveDbBlockChecker[txcontext.TxContext](cfg), + tracker.MakeDbLogger[txcontext.TxContext](cfg), ) } extensionList = append(extensionList, extra...) - extensionList = append(extensionList, []executor.Extension[*substate.Substate]{ + extensionList = append(extensionList, []executor.Extension[txcontext.TxContext]{ register.MakeRegisterProgress(cfg, 100_000), // RegisterProgress should be the first on the list = last to receive PostRun. // This is because it collects the error and records it externally. // If not, error that happen afterwards (e.g. on top of) will not be correcly recorded. - profiler.MakeThreadLocker[*substate.Substate](), - aidadb.MakeAidaDbManager[*substate.Substate](cfg), - profiler.MakeVirtualMachineStatisticsPrinter[*substate.Substate](cfg), - tracker.MakeProgressLogger[*substate.Substate](cfg, 15*time.Second), - tracker.MakeErrorLogger[*substate.Substate](cfg), + profiler.MakeThreadLocker[txcontext.TxContext](), + aidadb.MakeAidaDbManager[txcontext.TxContext](cfg), + profiler.MakeVirtualMachineStatisticsPrinter[txcontext.TxContext](cfg), + tracker.MakeProgressLogger[txcontext.TxContext](cfg, 15*time.Second), + tracker.MakeErrorLogger[txcontext.TxContext](cfg), tracker.MakeProgressTracker(cfg, 100_000), - primer.MakeStateDbPrimer[*substate.Substate](cfg), - profiler.MakeMemoryUsagePrinter[*substate.Substate](cfg), - profiler.MakeMemoryProfiler[*substate.Substate](cfg), + primer.MakeStateDbPrimer[txcontext.TxContext](cfg), + profiler.MakeMemoryUsagePrinter[txcontext.TxContext](cfg), + profiler.MakeMemoryProfiler[txcontext.TxContext](cfg), statedb.MakeStateDbPrepper(), statedb.MakeArchiveInquirer(cfg), - validator.MakeStateHashValidator[*substate.Substate](cfg), - statedb.MakeBlockEventEmitter[*substate.Substate](), + validator.MakeStateHashValidator[txcontext.TxContext](cfg), + statedb.MakeBlockEventEmitter[txcontext.TxContext](), validator.MakeLiveDbValidator(cfg), - profiler.MakeOperationProfiler[*substate.Substate](cfg), + profiler.MakeOperationProfiler[txcontext.TxContext](cfg), // block profile extension should be always last because: // 1) Pre-Func are called forwards so this is called last and diff --git a/cmd/aida-vm-sdb/run_substate_test.go b/cmd/aida-vm-sdb/run_substate_test.go index face7c401..900dd2574 100644 --- a/cmd/aida-vm-sdb/run_substate_test.go +++ b/cmd/aida-vm-sdb/run_substate_test.go @@ -8,6 +8,8 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" @@ -18,7 +20,7 @@ var testingAddress = common.Address{1} func TestVmSdb_Substate_AllDbEventsAreIssuedInOrder(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) cfg := &utils.Config{ First: 2, @@ -32,14 +34,14 @@ func TestVmSdb_Substate_AllDbEventsAreIssuedInOrder(t *testing.T) { // Simulate the execution of three transactions in two blocks. provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { // Block 2 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: emptyTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 2, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 2, Data: substatecontext.NewTxContext(emptyTx)}) // Block 3 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 3, Transaction: 1, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 3, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) // Block 4 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 4, Transaction: utils.PseudoTx, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 4, Transaction: utils.PseudoTx, Data: substatecontext.NewTxContext(emptyTx)}) return nil }) @@ -100,10 +102,10 @@ func TestVmSdb_Substate_AllDbEventsAreIssuedInOrder(t *testing.T) { func TestVmSdb_Substate_AllTransactionsAreProcessedInOrder(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) - ext := executor.NewMockExtension[*substate.Substate](ctrl) - processor := executor.NewMockProcessor[*substate.Substate](ctrl) + ext := executor.NewMockExtension[txcontext.TxContext](ctrl) + processor := executor.NewMockProcessor[txcontext.TxContext](ctrl) cfg := &utils.Config{ First: 2, Last: 4, @@ -115,14 +117,14 @@ func TestVmSdb_Substate_AllTransactionsAreProcessedInOrder(t *testing.T) { // Simulate the execution of three transactions in two blocks. provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { // Block 2 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: emptyTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 2, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 2, Data: substatecontext.NewTxContext(emptyTx)}) // Block 3 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 3, Transaction: 1, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 3, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) // Block 4 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 4, Transaction: utils.PseudoTx, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 4, Transaction: utils.PseudoTx, Data: substatecontext.NewTxContext(emptyTx)}) return nil }) @@ -131,55 +133,55 @@ func TestVmSdb_Substate_AllTransactionsAreProcessedInOrder(t *testing.T) { // Since we are running sequential mode with 1 worker, // all block and transactions need to be in order. gomock.InOrder( - ext.EXPECT().PreRun(executor.AtBlock[*substate.Substate](2), gomock.Any()), + ext.EXPECT().PreRun(executor.AtBlock[txcontext.TxContext](2), gomock.Any()), // Block 2 // Tx 1 - ext.EXPECT().PreBlock(executor.AtBlock[*substate.Substate](2), gomock.Any()), + ext.EXPECT().PreBlock(executor.AtBlock[txcontext.TxContext](2), gomock.Any()), db.EXPECT().BeginBlock(uint64(2)), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), db.EXPECT().PrepareSubstate(gomock.Any(), uint64(2)), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), // Tx 2 db.EXPECT().PrepareSubstate(gomock.Any(), uint64(2)), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), db.EXPECT().EndBlock(), - ext.EXPECT().PostBlock(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), + ext.EXPECT().PostBlock(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), // Block 3 - ext.EXPECT().PreBlock(executor.AtBlock[*substate.Substate](3), gomock.Any()), + ext.EXPECT().PreBlock(executor.AtBlock[txcontext.TxContext](3), gomock.Any()), db.EXPECT().BeginBlock(uint64(3)), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), db.EXPECT().PrepareSubstate(gomock.Any(), uint64(3)), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), db.EXPECT().EndBlock(), - ext.EXPECT().PostBlock(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), + ext.EXPECT().PostBlock(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), // Block 4 - ext.EXPECT().PreBlock(executor.AtBlock[*substate.Substate](4), gomock.Any()), + ext.EXPECT().PreBlock(executor.AtBlock[txcontext.TxContext](4), gomock.Any()), db.EXPECT().BeginBlock(uint64(4)), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), db.EXPECT().PrepareSubstate(gomock.Any(), uint64(4)), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), db.EXPECT().EndBlock(), - ext.EXPECT().PostBlock(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PostBlock(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostRun(executor.AtBlock[*substate.Substate](5), gomock.Any(), nil), + ext.EXPECT().PostRun(executor.AtBlock[txcontext.TxContext](5), gomock.Any(), nil), ) - if err := runSubstates(cfg, provider, db, processor, []executor.Extension[*substate.Substate]{ext}); err != nil { + if err := runSubstates(cfg, provider, db, processor, []executor.Extension[txcontext.TxContext]{ext}); err != nil { t.Errorf("run failed: %v", err) } } func TestVmSdb_Substate_ValidationDoesNotFailOnValidTransaction(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) cfg := &utils.Config{ First: 2, @@ -191,8 +193,8 @@ func TestVmSdb_Substate_ValidationDoesNotFailOnValidTransaction(t *testing.T) { provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { - return consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: testTx}) + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { + return consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(testTx)}) }) gomock.InOrder( @@ -230,7 +232,7 @@ func TestVmSdb_Substate_ValidationDoesNotFailOnValidTransaction(t *testing.T) { func TestVmSdb_Substate_ValidationFailsOnInvalidTransaction(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) cfg := &utils.Config{ First: 2, @@ -242,8 +244,8 @@ func TestVmSdb_Substate_ValidationFailsOnInvalidTransaction(t *testing.T) { provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { - return consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: testTx}) + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { + return consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(testTx)}) }) gomock.InOrder( diff --git a/cmd/aida-vm-sdb/run_tx_generator.go b/cmd/aida-vm-sdb/run_tx_generator.go index 4bfd8c5bc..31dfa9ca4 100644 --- a/cmd/aida-vm-sdb/run_tx_generator.go +++ b/cmd/aida-vm-sdb/run_tx_generator.go @@ -1,23 +1,14 @@ package main import ( - "time" - "github.com/Fantom-foundation/Aida/executor" - "github.com/Fantom-foundation/Aida/executor/extension/primer" - "github.com/Fantom-foundation/Aida/executor/extension/profiler" - "github.com/Fantom-foundation/Aida/executor/extension/statedb" - "github.com/Fantom-foundation/Aida/executor/extension/tracker" - "github.com/Fantom-foundation/Aida/executor/extension/validator" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" + "github.com/ethereum/go-ethereum/core/types" "github.com/urfave/cli/v2" ) -type GeneratedTransaction struct { - // todo fill with transaction info from the generator -} - // RunTxGenerator performs sequential block processing on a StateDb using transaction generator func RunTxGenerator(ctx *cli.Context) error { cfg, err := utils.NewConfig(ctx, utils.BlockRangeArgs) @@ -31,57 +22,43 @@ func RunTxGenerator(ctx *cli.Context) error { return runTransactions(cfg, nil, nil, false) } +func newGenerateData() txcontext.Transaction { + return &generateData{} +} + +type generateData struct { +} + +func (g generateData) GetBlockEnvironment() txcontext.BlockEnvironment { + //TODO implement me + panic("implement me") +} + +func (g generateData) GetMessage() types.Message { + //TODO implement me + panic("implement me") +} type txProcessor struct { cfg *utils.Config } -func (p txProcessor) Process(state executor.State[*GeneratedTransaction], ctx *executor.Context) error { +func (p txProcessor) Process(state executor.State[txcontext.Transaction], ctx *executor.Context) error { // todo apply data onto StateDb return nil } func runTransactions( cfg *utils.Config, - provider executor.Provider[*GeneratedTransaction], + provider executor.Provider[txcontext.Transaction], stateDb state.StateDB, disableStateDbExtension bool, ) error { // order of extensionList has to be maintained - var extensionList = []executor.Extension[*GeneratedTransaction]{ - profiler.MakeCpuProfiler[*GeneratedTransaction](cfg), - profiler.MakeDiagnosticServer[*GeneratedTransaction](cfg), + var extensionList = []executor.Extension[txcontext.Transaction]{ + // todo choose extensions } - if !disableStateDbExtension { - extensionList = append( - extensionList, - statedb.MakeStateDbManager[*GeneratedTransaction](cfg), - statedb.MakeLiveDbBlockChecker[*GeneratedTransaction](cfg), - ) - } - - extensionList = append(extensionList, []executor.Extension[*GeneratedTransaction]{ - profiler.MakeThreadLocker[*GeneratedTransaction](), - profiler.MakeVirtualMachineStatisticsPrinter[*GeneratedTransaction](cfg), - tracker.MakeProgressLogger[*GeneratedTransaction](cfg, 15*time.Second), - //tracker.MakeProgressTracker(cfg, 100_000), - primer.MakeStateDbPrimer[*GeneratedTransaction](cfg), - profiler.MakeMemoryUsagePrinter[*GeneratedTransaction](cfg), - profiler.MakeMemoryProfiler[*GeneratedTransaction](cfg), - //statedb.MakeStateDbPrepper(), - //statedb.MakeArchiveInquirer(cfg), - validator.MakeStateHashValidator[*GeneratedTransaction](cfg), - statedb.MakeBlockEventEmitter[*GeneratedTransaction](), - profiler.MakeOperationProfiler[*GeneratedTransaction](cfg), - // block profile extension should be always last because: - // 1) Pre-Func are called forwards so this is called last and - // 2) Post-Func are called backwards so this is called first - // that means the gap between time measurements will be as small as possible - //profiler.MakeBlockRuntimeAndGasCollector(cfg), - }..., - ) - return executor.NewExecutor(provider, cfg.LogLevel).Run( executor.Params{ From: int(cfg.First), diff --git a/cmd/aida-vm/run_vm.go b/cmd/aida-vm/run_vm.go index 6e225572d..51b07f054 100644 --- a/cmd/aida-vm/run_vm.go +++ b/cmd/aida-vm/run_vm.go @@ -9,8 +9,8 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension/tracker" "github.com/Fantom-foundation/Aida/executor/extension/validator" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" "github.com/urfave/cli/v2" ) @@ -38,29 +38,29 @@ func RunVm(ctx *cli.Context) error { // execution, in particular during unit tests. func run( cfg *utils.Config, - provider executor.Provider[*substate.Substate], + provider executor.Provider[txcontext.TxContext], stateDb state.StateDB, - processor executor.Processor[*substate.Substate], - extra []executor.Extension[*substate.Substate], + processor executor.Processor[txcontext.TxContext], + extra []executor.Extension[txcontext.TxContext], ) error { - extensions := []executor.Extension[*substate.Substate]{ - profiler.MakeCpuProfiler[*substate.Substate](cfg), - profiler.MakeDiagnosticServer[*substate.Substate](cfg), - profiler.MakeVirtualMachineStatisticsPrinter[*substate.Substate](cfg), + extensions := []executor.Extension[txcontext.TxContext]{ + profiler.MakeCpuProfiler[txcontext.TxContext](cfg), + profiler.MakeDiagnosticServer[txcontext.TxContext](cfg), + profiler.MakeVirtualMachineStatisticsPrinter[txcontext.TxContext](cfg), } if stateDb == nil { extensions = append( extensions, statedb.MakeTemporaryStatePrepper(cfg), - tracker.MakeDbLogger[*substate.Substate](cfg), + tracker.MakeDbLogger[txcontext.TxContext](cfg), ) } extensions = append( extensions, - tracker.MakeErrorLogger[*substate.Substate](cfg), - tracker.MakeProgressLogger[*substate.Substate](cfg, 15*time.Second), + tracker.MakeErrorLogger[txcontext.TxContext](cfg), + tracker.MakeProgressLogger[txcontext.TxContext](cfg, 15*time.Second), validator.MakeLiveDbValidator(cfg), ) extensions = append(extensions, extra...) diff --git a/cmd/aida-vm/run_vm_test.go b/cmd/aida-vm/run_vm_test.go index ab7152dc0..905509019 100644 --- a/cmd/aida-vm/run_vm_test.go +++ b/cmd/aida-vm/run_vm_test.go @@ -7,6 +7,8 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" @@ -17,7 +19,7 @@ var testingAddress = common.Address{1} func TestVm_AllDbEventsAreIssuedInOrder_Sequential(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) cfg := &utils.Config{ First: 2, @@ -32,14 +34,14 @@ func TestVm_AllDbEventsAreIssuedInOrder_Sequential(t *testing.T) { // Simulate the execution of three transactions in two blocks. provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { // Block 2 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: emptyTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 2, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 2, Data: substatecontext.NewTxContext(emptyTx)}) // Block 3 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 3, Transaction: 1, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 3, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) // Block 4 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 4, Transaction: utils.PseudoTx, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 4, Transaction: utils.PseudoTx, Data: substatecontext.NewTxContext(emptyTx)}) return nil }) @@ -80,7 +82,7 @@ func TestVm_AllDbEventsAreIssuedInOrder_Sequential(t *testing.T) { func TestVm_AllDbEventsAreIssuedInOrder_Parallel(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) cfg := &utils.Config{ First: 2, @@ -95,14 +97,14 @@ func TestVm_AllDbEventsAreIssuedInOrder_Parallel(t *testing.T) { // Simulate the execution of three transactions in two blocks. provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { // Block 2 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: emptyTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 2, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 2, Data: substatecontext.NewTxContext(emptyTx)}) // Block 3 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 3, Transaction: 1, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 3, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) // Block 4 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 4, Transaction: utils.PseudoTx, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 4, Transaction: utils.PseudoTx, Data: substatecontext.NewTxContext(emptyTx)}) return nil }) @@ -152,9 +154,9 @@ func TestVm_AllDbEventsAreIssuedInOrder_Parallel(t *testing.T) { func TestVm_AllTransactionsAreProcessedInOrder_Sequential(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) - processor := executor.NewMockProcessor[*substate.Substate](ctrl) - ext := executor.NewMockExtension[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) + processor := executor.NewMockProcessor[txcontext.TxContext](ctrl) + ext := executor.NewMockExtension[txcontext.TxContext](ctrl) cfg := &utils.Config{ First: 2, Last: 4, @@ -168,14 +170,14 @@ func TestVm_AllTransactionsAreProcessedInOrder_Sequential(t *testing.T) { // Simulate the execution of three transactions in two blocks. provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { // Block 2 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: emptyTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 2, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 2, Data: substatecontext.NewTxContext(emptyTx)}) // Block 3 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 3, Transaction: 1, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 3, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) // Block 4 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 4, Transaction: utils.PseudoTx, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 4, Transaction: utils.PseudoTx, Data: substatecontext.NewTxContext(emptyTx)}) return nil }) @@ -185,39 +187,39 @@ func TestVm_AllTransactionsAreProcessedInOrder_Sequential(t *testing.T) { // all blocks and transactions need to be in order. gomock.InOrder( - ext.EXPECT().PreRun(executor.AtBlock[*substate.Substate](2), gomock.Any()), + ext.EXPECT().PreRun(executor.AtBlock[txcontext.TxContext](2), gomock.Any()), // Block 2 // Tx 1 - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), // Tx 2 - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), // Block 3 - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), // Block 4 - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostRun(executor.AtBlock[*substate.Substate](5), gomock.Any(), nil), + ext.EXPECT().PostRun(executor.AtBlock[txcontext.TxContext](5), gomock.Any(), nil), ) - run(cfg, provider, nil, processor, []executor.Extension[*substate.Substate]{ext}) + run(cfg, provider, nil, processor, []executor.Extension[txcontext.TxContext]{ext}) } func TestVm_AllTransactionsAreProcessedInOrder_Parallel(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) - processor := executor.NewMockProcessor[*substate.Substate](ctrl) - ext := executor.NewMockExtension[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) + processor := executor.NewMockProcessor[txcontext.TxContext](ctrl) + ext := executor.NewMockExtension[txcontext.TxContext](ctrl) cfg := &utils.Config{ First: 2, Last: 4, @@ -231,19 +233,19 @@ func TestVm_AllTransactionsAreProcessedInOrder_Parallel(t *testing.T) { // Simulate the execution of three transactions in two blocks. provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { // Block 2 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: emptyTx}) - consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 2, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 2, Data: substatecontext.NewTxContext(emptyTx)}) // Block 3 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 3, Transaction: 1, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 3, Transaction: 1, Data: substatecontext.NewTxContext(emptyTx)}) // Block 4 - consumer(executor.TransactionInfo[*substate.Substate]{Block: 4, Transaction: utils.PseudoTx, Data: emptyTx}) + consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 4, Transaction: utils.PseudoTx, Data: substatecontext.NewTxContext(emptyTx)}) return nil }) - pre := ext.EXPECT().PreRun(executor.AtBlock[*substate.Substate](2), gomock.Any()) - post := ext.EXPECT().PostRun(executor.AtBlock[*substate.Substate](5), gomock.Any(), nil) + pre := ext.EXPECT().PreRun(executor.AtBlock[txcontext.TxContext](2), gomock.Any()) + post := ext.EXPECT().PostRun(executor.AtBlock[txcontext.TxContext](5), gomock.Any(), nil) // The expectation is that all of those transactions // are properly opened, prepared, executed, and closed. @@ -254,18 +256,18 @@ func TestVm_AllTransactionsAreProcessedInOrder_Parallel(t *testing.T) { // Tx 1 gomock.InOrder( pre, - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](2, 1), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](2, 1), gomock.Any()), post, ) // Tx 2 gomock.InOrder( pre, - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](2, 2), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](2, 2), gomock.Any()), post, ) @@ -273,9 +275,9 @@ func TestVm_AllTransactionsAreProcessedInOrder_Parallel(t *testing.T) { // Tx 1 gomock.InOrder( pre, - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](3, 1), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](3, 1), gomock.Any()), post, ) @@ -283,20 +285,20 @@ func TestVm_AllTransactionsAreProcessedInOrder_Parallel(t *testing.T) { // Tx 1 gomock.InOrder( pre, - ext.EXPECT().PreTransaction(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), - processor.EXPECT().Process(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), - ext.EXPECT().PostTransaction(executor.AtTransaction[*substate.Substate](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PreTransaction(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), + processor.EXPECT().Process(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), + ext.EXPECT().PostTransaction(executor.AtTransaction[txcontext.TxContext](4, utils.PseudoTx), gomock.Any()), post, ) - if err := run(cfg, provider, nil, processor, []executor.Extension[*substate.Substate]{ext}); err != nil { + if err := run(cfg, provider, nil, processor, []executor.Extension[txcontext.TxContext]{ext}); err != nil { t.Errorf("run failed: %v", err) } } func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Sequential(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) cfg := &utils.Config{ First: 2, @@ -309,8 +311,8 @@ func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Sequential(t *testing.T) provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { - return consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: testTx}) + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { + return consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(testTx)}) }) gomock.InOrder( @@ -346,7 +348,7 @@ func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Sequential(t *testing.T) func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Parallel(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) cfg := &utils.Config{ First: 2, @@ -359,8 +361,8 @@ func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Parallel(t *testing.T) { provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { - return consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: testTx}) + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { + return consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(testTx)}) }) gomock.InOrder( @@ -396,7 +398,7 @@ func TestVmAdb_ValidationDoesNotFailOnValidTransaction_Parallel(t *testing.T) { func TestVm_ValidationFailsOnInvalidTransaction_Sequential(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) cfg := &utils.Config{ First: 2, @@ -409,8 +411,8 @@ func TestVm_ValidationFailsOnInvalidTransaction_Sequential(t *testing.T) { provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { - return consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: testTx}) + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { + return consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(testTx)}) }) gomock.InOrder( @@ -436,7 +438,7 @@ func TestVm_ValidationFailsOnInvalidTransaction_Sequential(t *testing.T) { func TestVm_ValidationFailsOnInvalidTransaction_Parallel(t *testing.T) { ctrl := gomock.NewController(t) - provider := executor.NewMockProvider[*substate.Substate](ctrl) + provider := executor.NewMockProvider[txcontext.TxContext](ctrl) db := state.NewMockStateDB(ctrl) cfg := &utils.Config{ First: 2, @@ -449,8 +451,8 @@ func TestVm_ValidationFailsOnInvalidTransaction_Parallel(t *testing.T) { provider.EXPECT(). Run(2, 5, gomock.Any()). - DoAndReturn(func(_ int, _ int, consumer executor.Consumer[*substate.Substate]) error { - return consumer(executor.TransactionInfo[*substate.Substate]{Block: 2, Transaction: 1, Data: testTx}) + DoAndReturn(func(_ int, _ int, consumer executor.Consumer[txcontext.TxContext]) error { + return consumer(executor.TransactionInfo[txcontext.TxContext]{Block: 2, Transaction: 1, Data: substatecontext.NewTxContext(testTx)}) }) gomock.InOrder( diff --git a/cmd/util-db/db/lachesis-update.go b/cmd/util-db/db/lachesis-update.go index fd3d766b0..6a98acd81 100644 --- a/cmd/util-db/db/lachesis-update.go +++ b/cmd/util-db/db/lachesis-update.go @@ -83,7 +83,7 @@ func lachesisUpdate(ctx *cli.Context) error { len(untrackedState)) substate.PutSubstate(lachesisLastBlock, utils.PseudoTx, transitionTx) } else { - log.Warningf("Transition transaction has already been produced. Skip writing") + log.Warningf("Transition tx has already been produced. Skip writing") } return nil } diff --git a/executor/extension/primer/primer.go b/executor/extension/primer/primer.go index 527ada6e7..30606dbbb 100644 --- a/executor/extension/primer/primer.go +++ b/executor/extension/primer/primer.go @@ -7,6 +7,7 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension" "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/google/martian/log" @@ -92,7 +93,7 @@ func (p *stateDbPrimer[T]) prime(stateDb state.StateDB) error { // Prime StateDB if totalSize+incrementalSize > p.cfg.UpdateBufferSize { p.log.Infof("\tPriming...") - if err = p.ctx.PrimeStateDB(update, stateDb); err != nil { + if err = p.ctx.PrimeStateDB(substatecontext.NewWorldState(update), stateDb); err != nil { return fmt.Errorf("cannot prime state-db; %v", err) } @@ -121,7 +122,7 @@ func (p *stateDbPrimer[T]) prime(stateDb state.StateDB) error { // if update set is not empty, prime the remaining if len(update) > 0 { - if err = p.ctx.PrimeStateDB(update, stateDb); err != nil { + if err = p.ctx.PrimeStateDB(substatecontext.NewWorldState(update), stateDb); err != nil { return fmt.Errorf("cannot prime state-db; %v", err) } update = make(substate.SubstateAlloc) @@ -140,7 +141,7 @@ func (p *stateDbPrimer[T]) prime(stateDb state.StateDB) error { if hasPrimed { p.ctx.SuicideAccounts(stateDb, deletedAccounts) } - if err = p.ctx.PrimeStateDB(update, stateDb); err != nil { + if err = p.ctx.PrimeStateDB(substatecontext.NewWorldState(update), stateDb); err != nil { return fmt.Errorf("cannot prime state-db; %v", err) } } diff --git a/executor/extension/primer/primer_test.go b/executor/extension/primer/primer_test.go index a92ae3ea4..fa1c2bfe3 100644 --- a/executor/extension/primer/primer_test.go +++ b/executor/extension/primer/primer_test.go @@ -10,7 +10,10 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension" "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" + "github.com/ethereum/go-ethereum/common" "go.uber.org/mock/gomock" ) @@ -101,32 +104,35 @@ func TestPrime_PrimeStateDB(t *testing.T) { }(sDB) // Generating randomized world state - ws, _ := utils.MakeWorldState(t) + alloc, _ := utils.MakeWorldState(t) + ws := substatecontext.NewWorldState(alloc) pc := utils.NewPrimeContext(cfg, sDB, log) // Priming state DB pc.PrimeStateDB(ws, sDB) // Checks if state DB was primed correctly - for key, account := range ws { - if sDB.GetBalance(key).Cmp(account.Balance) != 0 { - t.Fatalf("failed to prime account balance; Is: %v; Should be: %v", sDB.GetBalance(key), account.Balance) + ws.ForEachAccount(func(addr common.Address, acc txcontext.Account) { + if sDB.GetBalance(addr).Cmp(acc.GetBalance()) != 0 { + t.Fatalf("failed to prime account balance; Is: %v; Should be: %v", sDB.GetBalance(addr), acc.GetBalance()) } - if sDB.GetNonce(key) != account.Nonce { - t.Fatalf("failed to prime account nonce; Is: %v; Should be: %v", sDB.GetNonce(key), account.Nonce) + if sDB.GetNonce(addr) != acc.GetNonce() { + t.Fatalf("failed to prime account nonce; Is: %v; Should be: %v", sDB.GetNonce(addr), acc.GetNonce()) } - if bytes.Compare(sDB.GetCode(key), account.Code) != 0 { - t.Fatalf("failed to prime account code; Is: %v; Should be: %v", sDB.GetCode(key), account.Code) + if bytes.Compare(sDB.GetCode(addr), acc.GetCode()) != 0 { + t.Fatalf("failed to prime account code; Is: %v; Should be: %v", sDB.GetCode(addr), acc.GetCode()) } - for sKey, sValue := range account.Storage { - if sDB.GetState(key, sKey) != sValue { - t.Fatalf("failed to prime account storage; Is: %v; Should be: %v", sDB.GetState(key, sKey), sValue) + acc.ForEachStorage(func(keyHash common.Hash, valueHash common.Hash) { + if sDB.GetState(addr, keyHash) != valueHash { + t.Fatalf("failed to prime account storage; Is: %v; Should be: %v", sDB.GetState(addr, keyHash), valueHash) } - } - } + }) + + }) + }) } } diff --git a/executor/extension/primer/tx_primer.go b/executor/extension/primer/tx_primer.go index 984f8dd48..5405a210e 100644 --- a/executor/extension/primer/tx_primer.go +++ b/executor/extension/primer/tx_primer.go @@ -4,32 +4,32 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/executor/extension" "github.com/Fantom-foundation/Aida/logger" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" ) // MakeTxPrimer creates an extension that primes StateDb before each transaction -func MakeTxPrimer(cfg *utils.Config) executor.Extension[*substate.Substate] { +func MakeTxPrimer(cfg *utils.Config) executor.Extension[txcontext.TxContext] { return makeTxPrimer(cfg, logger.NewLogger(cfg.LogLevel, "TxPrimer")) } -func makeTxPrimer(cfg *utils.Config, log logger.Logger) executor.Extension[*substate.Substate] { +func makeTxPrimer(cfg *utils.Config, log logger.Logger) executor.Extension[txcontext.TxContext] { return &txPrimer{cfg: cfg, log: log} } type txPrimer struct { - extension.NilExtension[*substate.Substate] + extension.NilExtension[txcontext.TxContext] primeCtx *utils.PrimeContext cfg *utils.Config log logger.Logger } -func (p *txPrimer) PreRun(_ executor.State[*substate.Substate], ctx *executor.Context) error { +func (p *txPrimer) PreRun(_ executor.State[txcontext.TxContext], ctx *executor.Context) error { p.primeCtx = utils.NewPrimeContext(p.cfg, ctx.State, p.log) return nil } // PreTransaction primes StateDb -func (p *txPrimer) PreTransaction(state executor.State[*substate.Substate], ctx *executor.Context) error { - return p.primeCtx.PrimeStateDB(state.Data.InputAlloc, ctx.State) +func (p *txPrimer) PreTransaction(state executor.State[txcontext.TxContext], ctx *executor.Context) error { + return p.primeCtx.PrimeStateDB(state.Data.GetInputState(), ctx.State) } diff --git a/executor/extension/profiler/block_runtime_and_gas_collector.go b/executor/extension/profiler/block_runtime_and_gas_collector.go index 468d35442..2c568d021 100644 --- a/executor/extension/profiler/block_runtime_and_gas_collector.go +++ b/executor/extension/profiler/block_runtime_and_gas_collector.go @@ -8,13 +8,13 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension" "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/profile/blockprofile" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" ) -func MakeBlockRuntimeAndGasCollector(cfg *utils.Config) executor.Extension[*substate.Substate] { +func MakeBlockRuntimeAndGasCollector(cfg *utils.Config) executor.Extension[txcontext.TxContext] { if !cfg.ProfileBlocks { - return extension.NilExtension[*substate.Substate]{} + return extension.NilExtension[txcontext.TxContext]{} } return &BlockRuntimeAndGasCollector{ cfg: cfg, @@ -23,7 +23,7 @@ func MakeBlockRuntimeAndGasCollector(cfg *utils.Config) executor.Extension[*subs } type BlockRuntimeAndGasCollector struct { - extension.NilExtension[*substate.Substate] + extension.NilExtension[txcontext.TxContext] log logger.Logger cfg *utils.Config profileDb *blockprofile.ProfileDB @@ -33,7 +33,7 @@ type BlockRuntimeAndGasCollector struct { } // PreRun prepares the ProfileDB -func (b *BlockRuntimeAndGasCollector) PreRun(executor.State[*substate.Substate], *executor.Context) error { +func (b *BlockRuntimeAndGasCollector) PreRun(executor.State[txcontext.TxContext], *executor.Context) error { var err error b.profileDb, err = blockprofile.NewProfileDB(b.cfg.ProfileDB) if err != nil { @@ -50,13 +50,13 @@ func (b *BlockRuntimeAndGasCollector) PreRun(executor.State[*substate.Substate], } // PreTransaction resets the transaction timer. -func (b *BlockRuntimeAndGasCollector) PreTransaction(executor.State[*substate.Substate], *executor.Context) error { +func (b *BlockRuntimeAndGasCollector) PreTransaction(executor.State[txcontext.TxContext], *executor.Context) error { b.txTimer = time.Now() return nil } // PostTransaction records tx into profile context. -func (b *BlockRuntimeAndGasCollector) PostTransaction(state executor.State[*substate.Substate], _ *executor.Context) error { +func (b *BlockRuntimeAndGasCollector) PostTransaction(state executor.State[txcontext.TxContext], _ *executor.Context) error { err := b.ctx.RecordTransaction(state, time.Since(b.txTimer)) if err != nil { return fmt.Errorf("cannot record transaction; %v", err) @@ -65,14 +65,14 @@ func (b *BlockRuntimeAndGasCollector) PostTransaction(state executor.State[*subs } // PreBlock resets the block times and profile context. -func (b *BlockRuntimeAndGasCollector) PreBlock(executor.State[*substate.Substate], *executor.Context) error { +func (b *BlockRuntimeAndGasCollector) PreBlock(executor.State[txcontext.TxContext], *executor.Context) error { b.ctx = blockprofile.NewContext() b.blockTimer = time.Now() return nil } // PostBlock extracts data from profile context and writes them to ProfileDB. -func (b *BlockRuntimeAndGasCollector) PostBlock(state executor.State[*substate.Substate], _ *executor.Context) error { +func (b *BlockRuntimeAndGasCollector) PostBlock(state executor.State[txcontext.TxContext], _ *executor.Context) error { data, err := b.ctx.GetProfileData(uint64(state.Block), time.Since(b.blockTimer)) if err != nil { return fmt.Errorf("cannot get profile data from context; %v", err) @@ -87,7 +87,7 @@ func (b *BlockRuntimeAndGasCollector) PostBlock(state executor.State[*substate.S } // PostRun closes ProfileDB -func (b *BlockRuntimeAndGasCollector) PostRun(executor.State[*substate.Substate], *executor.Context, error) error { +func (b *BlockRuntimeAndGasCollector) PostRun(executor.State[txcontext.TxContext], *executor.Context, error) error { defer func() { if r := recover(); r != nil { b.log.Errorf("recovered panic in block-profiler; %v", r) diff --git a/executor/extension/profiler/block_runtime_and_gas_collector_test.go b/executor/extension/profiler/block_runtime_and_gas_collector_test.go index 721227c60..fe9db81ed 100644 --- a/executor/extension/profiler/block_runtime_and_gas_collector_test.go +++ b/executor/extension/profiler/block_runtime_and_gas_collector_test.go @@ -7,15 +7,15 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/executor/extension" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" ) func TestBlockProfilerExtension_NoProfileIsCollectedIfDisabled(t *testing.T) { config := &utils.Config{} ext := MakeBlockRuntimeAndGasCollector(config) - if _, ok := ext.(extension.NilExtension[*substate.Substate]); !ok { + if _, ok := ext.(extension.NilExtension[txcontext.TxContext]); !ok { t.Errorf("profiler is enabled although not set in configuration") } } @@ -28,7 +28,7 @@ func TestBlockProfilerExtension_ProfileDbIsCreated(t *testing.T) { ext := MakeBlockRuntimeAndGasCollector(config) - if err := ext.PreRun(executor.State[*substate.Substate]{}, nil); err != nil { + if err := ext.PreRun(executor.State[txcontext.TxContext]{}, nil); err != nil { t.Fatalf("unexpected error during pre-run; %v", err) } diff --git a/executor/extension/profiler/operation_profiler_test.go b/executor/extension/profiler/operation_profiler_test.go index 88fb2719a..b0a416ac7 100644 --- a/executor/extension/profiler/operation_profiler_test.go +++ b/executor/extension/profiler/operation_profiler_test.go @@ -37,7 +37,7 @@ func getTotalOpCount(a *analytics.IncrementalAnalytics) int { // This generates exactly one call per operation and test if the following are true: // - That op profiler correctly proxies any StateDB implementation -// - This is repeated for each depth level -> interval, block and transaction +// - This is repeated for each depth level -> interval, block and txcontext // - Call each function exactly once // - Make explicit the fact that some StateDB are not proxied (see black list below) diff --git a/executor/extension/register/register_progress.go b/executor/extension/register/register_progress.go index ae3c3aaf7..f2a9099cc 100644 --- a/executor/extension/register/register_progress.go +++ b/executor/extension/register/register_progress.go @@ -11,8 +11,8 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension" "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" ) const ( @@ -42,9 +42,9 @@ const ( // MakeRegisterProgress creates an extention that // 1. Track Progress e.g. ProgressTracker // 2. Register the intermediate results to an external service (sqlite3 db) -func MakeRegisterProgress(cfg *utils.Config, reportFrequency int) executor.Extension[*substate.Substate] { +func MakeRegisterProgress(cfg *utils.Config, reportFrequency int) executor.Extension[txcontext.TxContext] { if cfg.RegisterRun == "" { - return extension.NilExtension[*substate.Substate]{} + return extension.NilExtension[txcontext.TxContext]{} } if reportFrequency == 0 { @@ -83,7 +83,7 @@ func MakeRegisterProgress(cfg *utils.Config, reportFrequency int) executor.Exten // registerProgress logs progress every XXX blocks depending on reportFrequency. // Default is 100_000 blocks. This is mainly used for gathering information about process. type registerProgress struct { - extension.NilExtension[*substate.Substate] + extension.NilExtension[txcontext.TxContext] // Configuration cfg *utils.Config @@ -109,7 +109,7 @@ type registerProgress struct { meta *RunMetadata } -func (rp *registerProgress) PreRun(_ executor.State[*substate.Substate], ctx *executor.Context) error { +func (rp *registerProgress) PreRun(_ executor.State[txcontext.TxContext], ctx *executor.Context) error { now := time.Now() rp.startOfRun = now rp.lastUpdate = now @@ -120,8 +120,8 @@ func (rp *registerProgress) PreRun(_ executor.State[*substate.Substate], ctx *ex // PreBlock sends the state to the report goroutine. // We only care about total number of transactions we can do this here rather in Pre/PostTransaction. // -// This is done in PreBlock because some blocks do not have transaction. -func (rp *registerProgress) PreBlock(state executor.State[*substate.Substate], ctx *executor.Context) error { +// This is done in PreBlock because some blocks do not have txcontext. +func (rp *registerProgress) PreBlock(state executor.State[txcontext.TxContext], ctx *executor.Context) error { if uint64(state.Block) > rp.interval.End() { rp.memory = ctx.State.GetMemoryUsage() rp.ps.Print() @@ -133,21 +133,23 @@ func (rp *registerProgress) PreBlock(state executor.State[*substate.Substate], c } // PostTransaction increments number of transactions and saves gas used in last substate. -func (rp *registerProgress) PostTransaction(state executor.State[*substate.Substate], _ *executor.Context) error { +func (rp *registerProgress) PostTransaction(state executor.State[txcontext.TxContext], _ *executor.Context) error { + res := state.Data.GetReceipt() + rp.lock.Lock() defer rp.lock.Unlock() rp.totalTxCount++ rp.txCount++ - rp.totalGas += state.Data.Result.GasUsed - rp.gas += state.Data.Result.GasUsed + rp.totalGas += res.GetGasUsed() + rp.gas += res.GetGasUsed() return nil } // PostRun prints the remaining statistics and terminates any printer resources. -func (rp *registerProgress) PostRun(_ executor.State[*substate.Substate], ctx *executor.Context, err error) error { +func (rp *registerProgress) PostRun(_ executor.State[txcontext.TxContext], ctx *executor.Context, err error) error { rp.memory = ctx.State.GetMemoryUsage() rp.ps.Print() rp.Reset() diff --git a/executor/extension/register/register_progress_test.go b/executor/extension/register/register_progress_test.go index 3d51d2edc..0c4d5ef70 100644 --- a/executor/extension/register/register_progress_test.go +++ b/executor/extension/register/register_progress_test.go @@ -10,6 +10,8 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/executor/extension" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" @@ -62,7 +64,7 @@ func TestRegisterProgress_DoNothingIfDisabled(t *testing.T) { cfg := &utils.Config{} cfg.RegisterRun = "" ext := MakeRegisterProgress(cfg, 0) - if _, ok := ext.(extension.NilExtension[*substate.Substate]); !ok { + if _, ok := ext.(extension.NilExtension[txcontext.TxContext]); !ok { t.Errorf("RegisterProgress is enabled even though not disabled in configuration.") } } @@ -117,7 +119,7 @@ func TestRegisterProgress_InsertToDbIfEnabled(t *testing.T) { // expects [5-9]P[10-19]P[20-24]P, where P is print ext := MakeRegisterProgress(cfg, interval) - if _, err := ext.(extension.NilExtension[*substate.Substate]); err { + if _, err := ext.(extension.NilExtension[txcontext.TxContext]); err { t.Errorf("RegisterProgress is disabled even though enabled in configuration.") } @@ -141,10 +143,12 @@ func TestRegisterProgress_InsertToDbIfEnabled(t *testing.T) { stateDb.EXPECT().GetMemoryUsage().Return(&state.MemoryUsage{UsedBytes: 5555}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) + + sub := substatecontext.NewTxContext(s) for b := int(cfg.First); b < int(cfg.Last); b++ { - ext.PreBlock(executor.State[*substate.Substate]{Block: b, Data: s}, ctx) + ext.PreBlock(executor.State[txcontext.TxContext]{Block: b, Data: sub}, ctx) // check if a print happens here if b > int(itv.End()) { @@ -157,12 +161,12 @@ func TestRegisterProgress_InsertToDbIfEnabled(t *testing.T) { t.Errorf("Expected #Row: %d, Actual #Row: %d", expectedRowCount, len(stats)) } - ext.PreTransaction(executor.State[*substate.Substate]{Data: s}, ctx) - ext.PostTransaction(executor.State[*substate.Substate]{Data: s}, ctx) - ext.PostBlock(executor.State[*substate.Substate]{Block: b, Data: s}, ctx) + ext.PreTransaction(executor.State[txcontext.TxContext]{Data: sub}, ctx) + ext.PostTransaction(executor.State[txcontext.TxContext]{Data: sub}, ctx) + ext.PostBlock(executor.State[txcontext.TxContext]{Block: b, Data: sub}, ctx) } - ext.PostRun(executor.State[*substate.Substate]{}, ctx, nil) + ext.PostRun(executor.State[txcontext.TxContext]{}, ctx, nil) // check if a print happens here expectedRowCount++ @@ -251,14 +255,14 @@ func TestRegisterProgress_IfErrorRecordIntoMetadata(t *testing.T) { ) ext := MakeRegisterProgress(cfg, 123) - if _, err := ext.(extension.NilExtension[*substate.Substate]); err { + if _, err := ext.(extension.NilExtension[txcontext.TxContext]); err { t.Errorf("RegisterProgress is disabled even though enabled in configuration.") } // this is the run errorText := "This is one random error!" - ext.PreRun(executor.State[*substate.Substate]{}, ctx) - ext.PostRun(executor.State[*substate.Substate]{}, ctx, fmt.Errorf(errorText)) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) + ext.PostRun(executor.State[txcontext.TxContext]{}, ctx, fmt.Errorf(errorText)) // check if RunSucceed is recorded after postrun ms := []metadataResponse{} diff --git a/executor/extension/statedb/archive_inquirer.go b/executor/extension/statedb/archive_inquirer.go index 8c88d1c35..39498a928 100644 --- a/executor/extension/statedb/archive_inquirer.go +++ b/executor/extension/statedb/archive_inquirer.go @@ -12,19 +12,19 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension/validator" "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" ) // MakeArchiveInquirer creates an extension running historic queries against // archive states in the background to the main executor process. -func MakeArchiveInquirer(cfg *utils.Config) executor.Extension[*substate.Substate] { +func MakeArchiveInquirer(cfg *utils.Config) executor.Extension[txcontext.TxContext] { return makeArchiveInquirer(cfg, logger.NewLogger(cfg.LogLevel, "Archive Inquirer")) } -func makeArchiveInquirer(cfg *utils.Config, log logger.Logger) executor.Extension[*substate.Substate] { +func makeArchiveInquirer(cfg *utils.Config, log logger.Logger) executor.Extension[txcontext.TxContext] { if cfg.ArchiveQueryRate <= 0 { - return extension.NilExtension[*substate.Substate]{} + return extension.NilExtension[txcontext.TxContext]{} } return &archiveInquirer{ ArchiveDbProcessor: executor.MakeArchiveDbProcessor(cfg), @@ -38,7 +38,7 @@ func makeArchiveInquirer(cfg *utils.Config, log logger.Logger) executor.Extensio } type archiveInquirer struct { - extension.NilExtension[*substate.Substate] + extension.NilExtension[txcontext.TxContext] *executor.ArchiveDbProcessor cfg *utils.Config @@ -59,10 +59,10 @@ type archiveInquirer struct { gasCounter atomic.Uint64 totalQueryTimeMilliseconds atomic.Uint64 - validator executor.Extension[*substate.Substate] + validator executor.Extension[txcontext.TxContext] } -func (i *archiveInquirer) PreRun(_ executor.State[*substate.Substate], ctx *executor.Context) error { +func (i *archiveInquirer) PreRun(_ executor.State[txcontext.TxContext], ctx *executor.Context) error { if !i.cfg.ArchiveMode { i.finished.Signal() return fmt.Errorf("can not run archive queries without enabled archive (missing --%s flag)", utils.ArchiveModeFlag.Name) @@ -80,7 +80,7 @@ func (i *archiveInquirer) PreRun(_ executor.State[*substate.Substate], ctx *exec return nil } -func (i *archiveInquirer) PostTransaction(state executor.State[*substate.Substate], _ *executor.Context) error { +func (i *archiveInquirer) PostTransaction(state executor.State[txcontext.TxContext], _ *executor.Context) error { // We only sample the very first transaction in each block since other transactions // may depend on the effects of its predecessors in the same block. if state.Transaction != 0 { @@ -91,14 +91,14 @@ func (i *archiveInquirer) PostTransaction(state executor.State[*substate.Substat i.historyMutex.Lock() defer i.historyMutex.Unlock() i.history.Add(historicTransaction{ - block: state.Block - 1, - number: state.Transaction, - substate: state.Data, + block: state.Block - 1, + number: state.Transaction, + data: state.Data, }) return nil } -func (i *archiveInquirer) PostRun(executor.State[*substate.Substate], *executor.Context, error) error { +func (i *archiveInquirer) PostRun(executor.State[txcontext.TxContext], *executor.Context, error) error { i.finished.Signal() i.done.Wait() return nil @@ -132,35 +132,35 @@ func (i *archiveInquirer) runInquiry(errCh chan error) { } func (i *archiveInquirer) doInquiry(rnd *rand.Rand, errCh chan error) { - // Pick a random transaction that is covered by the current archive block height. - transaction, found := i.getRandomTransaction(rnd) + // Pick a random tx that is covered by the current archive block height. + tx, found := i.getRandomTransaction(rnd) for found { height, empty, err := i.state.GetArchiveBlockHeight() if err != nil { i.log.Warningf("failed to obtain archive block height: %v", err) return } - if !empty && uint64(transaction.block) <= height { + if !empty && uint64(tx.block) <= height { break } - transaction, found = i.getRandomTransaction(rnd) + tx, found = i.getRandomTransaction(rnd) } if !found { return } // Perform historic query. - archive, err := i.state.GetArchiveState(uint64(transaction.block)) + archive, err := i.state.GetArchiveState(uint64(tx.block)) if err != nil { - errCh <- fmt.Errorf("failed to obtain access to archive at block height %d: %v", transaction.block, err) + errCh <- fmt.Errorf("failed to obtain access to archive at block height %d: %v", tx.block, err) return } defer archive.Release() - state := executor.State[*substate.Substate]{ - Block: transaction.block, - Transaction: transaction.number, - Data: transaction.substate, + state := executor.State[txcontext.TxContext]{ + Block: tx.block, + Transaction: tx.number, + Data: tx.data, } ctx := &executor.Context{ Archive: archive, @@ -192,7 +192,7 @@ func (i *archiveInquirer) doInquiry(rnd *rand.Rand, errCh chan error) { } i.transactionCounter.Add(1) - i.gasCounter.Add(transaction.substate.Result.GasUsed) + i.gasCounter.Add(tx.data.GetReceipt().GetGasUsed()) i.totalQueryTimeMilliseconds.Add(uint64(duration.Milliseconds())) } @@ -231,9 +231,9 @@ func (i *archiveInquirer) runProgressReport() { } type historicTransaction struct { - block int - number int - substate *substate.Substate + block int + number int + data txcontext.TxContext } type circularBuffer[T any] struct { diff --git a/executor/extension/statedb/archive_inquirer_test.go b/executor/extension/statedb/archive_inquirer_test.go index cc94c46c0..7b08376d6 100644 --- a/executor/extension/statedb/archive_inquirer_test.go +++ b/executor/extension/statedb/archive_inquirer_test.go @@ -10,6 +10,8 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension" "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" @@ -19,7 +21,7 @@ import ( func TestArchiveInquirer_DisabledIfNoQueryRateIsGiven(t *testing.T) { config := utils.Config{} ext := MakeArchiveInquirer(&config) - if _, ok := ext.(extension.NilExtension[*substate.Substate]); !ok { + if _, ok := ext.(extension.NilExtension[txcontext.TxContext]); !ok { t.Errorf("inquirer should not be active by default") } } @@ -31,7 +33,7 @@ func TestArchiveInquirer_ReportsErrorIfNoArchiveIsPresent(t *testing.T) { cfg.ArchiveQueryRate = 100 ext := makeArchiveInquirer(&cfg, log) - state := executor.State[*substate.Substate]{} + state := executor.State[txcontext.TxContext]{} if err := ext.PreRun(state, nil); err == nil { t.Errorf("expected an error, got nothing") } @@ -50,7 +52,7 @@ func TestArchiveInquirer_CanStartUpAndShutdownGracefully(t *testing.T) { cfg.ArchiveQueryRate = 100 ext := makeArchiveInquirer(&cfg, log) - state := executor.State[*substate.Substate]{} + state := executor.State[txcontext.TxContext]{} context := executor.Context{State: db} if err := ext.PreRun(state, &context); err != nil { @@ -73,7 +75,7 @@ func TestArchiveInquirer_RunsRandomTransactionsInBackground(t *testing.T) { cfg.ArchiveMaxQueryAge = 100 cfg.ChainID = utils.TestnetChainID - state := executor.State[*substate.Substate]{} + state := executor.State[txcontext.TxContext]{} context := executor.Context{State: db} substate1 := makeValidSubstate() @@ -126,9 +128,9 @@ func TestArchiveInquirer_RunsRandomTransactionsInBackground(t *testing.T) { } } -func makeValidSubstate() *substate.Substate { - // This Substate is a minimal substate that can be successfully processed. - return &substate.Substate{ +func makeValidSubstate() txcontext.TxContext { + // This Substate is a minimal data that can be successfully processed. + sub := &substate.Substate{ Env: &substate.SubstateEnv{ GasLimit: 100_000_000, }, @@ -141,6 +143,7 @@ func makeValidSubstate() *substate.Substate { GasUsed: 1, }, } + return substatecontext.NewTxContext(sub) } func TestCircularBuffer_EnforcesSize(t *testing.T) { diff --git a/executor/extension/statedb/archive_prepper.go b/executor/extension/statedb/archive_prepper.go index 7e8945219..d9e0c04e2 100644 --- a/executor/extension/statedb/archive_prepper.go +++ b/executor/extension/statedb/archive_prepper.go @@ -3,20 +3,19 @@ package statedb import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/executor/extension" - substate "github.com/Fantom-foundation/Substate" ) // MakeArchivePrepper creates an extension for retrieving archive. Archive is assigned to context.Archive. -func MakeArchivePrepper() executor.Extension[*substate.Substate] { - return &archivePrepper{} +func MakeArchivePrepper[T any]() executor.Extension[T] { + return &archivePrepper[T]{} } -type archivePrepper struct { - extension.NilExtension[*substate.Substate] +type archivePrepper[T any] struct { + extension.NilExtension[T] } // PreBlock sends needed archive to the processor. -func (r *archivePrepper) PreBlock(state executor.State[*substate.Substate], ctx *executor.Context) error { +func (r *archivePrepper[T]) PreBlock(state executor.State[T], ctx *executor.Context) error { var err error ctx.Archive, err = ctx.State.GetArchiveState(uint64(state.Block) - 1) if err != nil { @@ -27,7 +26,7 @@ func (r *archivePrepper) PreBlock(state executor.State[*substate.Substate], ctx } // PostBlock releases the Archive StateDb -func (r *archivePrepper) PostBlock(_ executor.State[*substate.Substate], ctx *executor.Context) error { +func (r *archivePrepper[T]) PostBlock(_ executor.State[T], ctx *executor.Context) error { ctx.Archive.Release() return nil } diff --git a/executor/extension/statedb/archive_prepper_test.go b/executor/extension/statedb/archive_prepper_test.go index fcb3790b8..7bbfaf999 100644 --- a/executor/extension/statedb/archive_prepper_test.go +++ b/executor/extension/statedb/archive_prepper_test.go @@ -5,12 +5,11 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/state" - substate "github.com/Fantom-foundation/Substate" "go.uber.org/mock/gomock" ) func TestArchivePrepper_ArchiveGetsReleasedInPostBlock(t *testing.T) { - ext := MakeArchivePrepper() + ext := MakeArchivePrepper[any]() ctrl := gomock.NewController(t) db := state.NewMockStateDB(ctrl) @@ -21,7 +20,7 @@ func TestArchivePrepper_ArchiveGetsReleasedInPostBlock(t *testing.T) { archive.EXPECT().Release(), ) - state := executor.State[*substate.Substate]{ + state := executor.State[any]{ Block: 2, } ctx := &executor.Context{ diff --git a/executor/extension/statedb/proxy_recorder_prepper.go b/executor/extension/statedb/proxy_recorder_prepper.go index f3ba6f011..d0dd0b554 100644 --- a/executor/extension/statedb/proxy_recorder_prepper.go +++ b/executor/extension/statedb/proxy_recorder_prepper.go @@ -9,29 +9,28 @@ import ( "github.com/Fantom-foundation/Aida/tracer/context" "github.com/Fantom-foundation/Aida/tracer/operation" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" ) // MakeProxyRecorderPrepper creates an extension which -// creates a temporary RecorderProxy before each transaction -func MakeProxyRecorderPrepper(cfg *utils.Config) executor.Extension[*substate.Substate] { - return makeProxyRecorderPrepper(cfg) +// creates a temporary RecorderProxy before each txcontext +func MakeProxyRecorderPrepper[T any](cfg *utils.Config) executor.Extension[T] { + return makeProxyRecorderPrepper[T](cfg) } -func makeProxyRecorderPrepper(cfg *utils.Config) *proxyRecorderPrepper { - return &proxyRecorderPrepper{ +func makeProxyRecorderPrepper[T any](cfg *utils.Config) *proxyRecorderPrepper[T] { + return &proxyRecorderPrepper[T]{ cfg: cfg, } } -type proxyRecorderPrepper struct { - extension.NilExtension[*substate.Substate] +type proxyRecorderPrepper[T any] struct { + extension.NilExtension[T] cfg *utils.Config rCtx *context.Record syncPeriod uint64 } -func (p *proxyRecorderPrepper) PreRun(state executor.State[*substate.Substate], _ *executor.Context) error { +func (p *proxyRecorderPrepper[T]) PreRun(state executor.State[T], _ *executor.Context) error { var err error p.rCtx, err = context.NewRecord(p.cfg.TraceFile, p.cfg.First) if err != nil { @@ -47,7 +46,7 @@ func (p *proxyRecorderPrepper) PreRun(state executor.State[*substate.Substate], return nil } -func (p *proxyRecorderPrepper) PreBlock(state executor.State[*substate.Substate], ctx *executor.Context) error { +func (p *proxyRecorderPrepper[T]) PreBlock(state executor.State[T], ctx *executor.Context) error { // calculate the syncPeriod for given block newSyncPeriod := uint64(state.Block) / p.cfg.SyncPeriodLength @@ -64,7 +63,7 @@ func (p *proxyRecorderPrepper) PreBlock(state executor.State[*substate.Substate] // PreTransaction checks whether ctx.State has not been overwritten by temporary prepper, // if so it creates RecorderProxy. -func (p *proxyRecorderPrepper) PreTransaction(_ executor.State[*substate.Substate], ctx *executor.Context) error { +func (p *proxyRecorderPrepper[T]) PreTransaction(_ executor.State[T], ctx *executor.Context) error { // if ctx.State has not been change, no need to slow down the app by creating new Proxy if _, ok := ctx.State.(*proxy.RecorderProxy); ok { return nil @@ -74,12 +73,12 @@ func (p *proxyRecorderPrepper) PreTransaction(_ executor.State[*substate.Substat return nil } -func (p *proxyRecorderPrepper) PostBlock(executor.State[*substate.Substate], *executor.Context) error { +func (p *proxyRecorderPrepper[T]) PostBlock(executor.State[T], *executor.Context) error { operation.WriteOp(p.rCtx, operation.NewEndBlock()) return nil } -func (p *proxyRecorderPrepper) PostRun(_ executor.State[*substate.Substate], ctx *executor.Context, err error) error { +func (p *proxyRecorderPrepper[T]) PostRun(_ executor.State[T], ctx *executor.Context, err error) error { operation.WriteOp(p.rCtx, operation.NewEndSyncPeriod()) p.rCtx.Close() return nil diff --git a/executor/extension/statedb/proxy_recorder_prepper_test.go b/executor/extension/statedb/proxy_recorder_prepper_test.go index a744e0783..080ea673a 100644 --- a/executor/extension/statedb/proxy_recorder_prepper_test.go +++ b/executor/extension/statedb/proxy_recorder_prepper_test.go @@ -8,7 +8,6 @@ import ( "github.com/Fantom-foundation/Aida/state" "github.com/Fantom-foundation/Aida/state/proxy" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" "go.uber.org/mock/gomock" ) @@ -18,16 +17,16 @@ func TestTemporaryProxyRecorderPrepper_PreTransactionCreatesRecorderProxy(t *tes cfg.TraceFile = path cfg.SyncPeriodLength = 1 - p := MakeProxyRecorderPrepper(cfg) + p := MakeProxyRecorderPrepper[any](cfg) ctx := &executor.Context{} - err := p.PreRun(executor.State[*substate.Substate]{}, ctx) + err := p.PreRun(executor.State[any]{}, ctx) if err != nil { t.Fatalf("unexpected error; %v", err) } - err = p.PreTransaction(executor.State[*substate.Substate]{}, ctx) + err = p.PreTransaction(executor.State[any]{}, ctx) if err != nil { t.Fatalf("unexpected error; %v", err) } @@ -38,7 +37,7 @@ func TestTemporaryProxyRecorderPrepper_PreTransactionCreatesRecorderProxy(t *tes } // close the file gracefully - err = p.PostRun(executor.State[*substate.Substate]{}, ctx, nil) + err = p.PostRun(executor.State[any]{}, ctx, nil) if err != nil { t.Fatalf("unexpected error; %v", err) } @@ -50,21 +49,21 @@ func TestProxyRecorderPrepper_PreBlockWritesABeginBlockOperation(t *testing.T) { cfg.TraceFile = path cfg.SyncPeriodLength = 1 - p := makeProxyRecorderPrepper(cfg) + p := makeProxyRecorderPrepper[any](cfg) ctx := &executor.Context{} - err := p.PreRun(executor.State[*substate.Substate]{}, ctx) + err := p.PreRun(executor.State[any]{}, ctx) if err != nil { t.Fatalf("unexpected error; %v", err) } - err = p.PreTransaction(executor.State[*substate.Substate]{}, ctx) + err = p.PreTransaction(executor.State[any]{}, ctx) if err != nil { t.Fatalf("unexpected error; %v", err) } - err = p.PreBlock(executor.State[*substate.Substate]{}, ctx) + err = p.PreBlock(executor.State[any]{}, ctx) if err != nil { t.Fatalf("unexpected error; %v", err) } @@ -89,21 +88,21 @@ func TestProxyRecorderPrepper_PostBlockWritesAnEndBlockOperation(t *testing.T) { cfg.TraceFile = path cfg.SyncPeriodLength = 1 - p := makeProxyRecorderPrepper(cfg) + p := makeProxyRecorderPrepper[any](cfg) ctx := &executor.Context{} - err := p.PreRun(executor.State[*substate.Substate]{}, ctx) + err := p.PreRun(executor.State[any]{}, ctx) if err != nil { t.Fatalf("unexpected error; %v", err) } - err = p.PreTransaction(executor.State[*substate.Substate]{}, ctx) + err = p.PreTransaction(executor.State[any]{}, ctx) if err != nil { t.Fatalf("unexpected error; %v", err) } - err = p.PostBlock(executor.State[*substate.Substate]{}, ctx) + err = p.PostBlock(executor.State[any]{}, ctx) if err != nil { t.Fatalf("unexpected error; %v", err) } @@ -128,17 +127,17 @@ func TestProxyRecorderPrepper_PostRunWritesAnEndSynchPeriodOperation(t *testing. cfg.TraceFile = path cfg.SyncPeriodLength = 1 - p := MakeProxyRecorderPrepper(cfg) + p := MakeProxyRecorderPrepper[any](cfg) ctx := &executor.Context{} - err := p.PreRun(executor.State[*substate.Substate]{}, ctx) + err := p.PreRun(executor.State[any]{}, ctx) if err != nil { t.Fatalf("unexpected error; %v", err) } // close the file gracefully - err = p.PostRun(executor.State[*substate.Substate]{}, ctx, nil) + err = p.PostRun(executor.State[any]{}, ctx, nil) if err != nil { t.Fatalf("unexpected error; %v", err) } @@ -164,10 +163,10 @@ func TestProxyRecorderPrepper_PreTransactionCreatesNewLoggerProxy(t *testing.T) ctx := new(executor.Context) ctx.State = db - ext := MakeProxyRecorderPrepper(cfg) + ext := MakeProxyRecorderPrepper[any](cfg) // ctx.State is not yet a RecorderProxy hence PreTransaction assigns it - err := ext.PreTransaction(executor.State[*substate.Substate]{}, ctx) + err := ext.PreTransaction(executor.State[any]{}, ctx) if err != nil { t.Fatalf("pre-transaction failed; %v", err) } @@ -189,10 +188,10 @@ func TestProxyRecorderPrepper_PreTransactionDoesNotCreateNewLoggerProxy(t *testi ctx := new(executor.Context) ctx.State = db - ext := MakeProxyRecorderPrepper(cfg) + ext := MakeProxyRecorderPrepper[any](cfg) // first call PreTransaction to assign the proxy - err := ext.PreTransaction(executor.State[*substate.Substate]{}, ctx) + err := ext.PreTransaction(executor.State[any]{}, ctx) if err != nil { t.Fatalf("pre-transaction failed; %v", err) } @@ -201,7 +200,7 @@ func TestProxyRecorderPrepper_PreTransactionDoesNotCreateNewLoggerProxy(t *testi originalDb := ctx.State // then make sure it is not re-assigned again - err = ext.PreTransaction(executor.State[*substate.Substate]{}, ctx) + err = ext.PreTransaction(executor.State[any]{}, ctx) if err != nil { t.Fatalf("pre-transaction failed; %v", err) } diff --git a/executor/extension/statedb/state_prepper.go b/executor/extension/statedb/state_prepper.go index 2b033a143..b60269d60 100644 --- a/executor/extension/statedb/state_prepper.go +++ b/executor/extension/statedb/state_prepper.go @@ -3,24 +3,25 @@ package statedb import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/executor/extension" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" ) // MakeStateDbPrepper creates an executor extension calling PrepareSubstate on // an optional StateDB instance before each transaction of an execution. Its main -// purpose is to support Aida's in-memory DB implementation by feeding it substate +// purpose is to support Aida's in-memory DB implementation by feeding it data // information before each transaction in tools like `aida-vm-sdb`. -func MakeStateDbPrepper() executor.Extension[*substate.Substate] { +func MakeStateDbPrepper() executor.Extension[txcontext.TxContext] { return &statePrepper{} } type statePrepper struct { - extension.NilExtension[*substate.Substate] + extension.NilExtension[txcontext.TxContext] } -func (e *statePrepper) PreTransaction(state executor.State[*substate.Substate], ctx *executor.Context) error { +func (e *statePrepper) PreTransaction(state executor.State[txcontext.TxContext], ctx *executor.Context) error { if ctx != nil && ctx.State != nil && state.Data != nil { - ctx.State.PrepareSubstate(&state.Data.InputAlloc, uint64(state.Block)) + alloc := state.Data.GetInputState() + ctx.State.PrepareSubstate(alloc, uint64(state.Block)) } return nil } diff --git a/executor/extension/statedb/state_prepper_test.go b/executor/extension/statedb/state_prepper_test.go index c86f0af67..339a1af56 100644 --- a/executor/extension/statedb/state_prepper_test.go +++ b/executor/extension/statedb/state_prepper_test.go @@ -5,6 +5,8 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" "go.uber.org/mock/gomock" @@ -14,25 +16,25 @@ func TestStatePrepper_PreparesStateBeforeEachTransaction(t *testing.T) { ctrl := gomock.NewController(t) db := state.NewMockStateDB(ctrl) - allocA := substate.SubstateAlloc{common.Address{1}: nil} - allocB := substate.SubstateAlloc{common.Address{2}: nil} + allocA := substatecontext.NewTxContext(&substate.Substate{InputAlloc: substate.SubstateAlloc{common.Address{1}: &substate.SubstateAccount{}}}) + allocB := substatecontext.NewTxContext(&substate.Substate{InputAlloc: substate.SubstateAlloc{common.Address{2}: &substate.SubstateAccount{}}}) ctx := &executor.Context{State: db} gomock.InOrder( - db.EXPECT().PrepareSubstate(&allocA, uint64(5)), - db.EXPECT().PrepareSubstate(&allocB, uint64(7)), + db.EXPECT().PrepareSubstate(allocA.GetInputState(), uint64(5)), + db.EXPECT().PrepareSubstate(allocB.GetInputState(), uint64(7)), ) prepper := MakeStateDbPrepper() - prepper.PreTransaction(executor.State[*substate.Substate]{ + prepper.PreTransaction(executor.State[txcontext.TxContext]{ Block: 5, - Data: &substate.Substate{InputAlloc: allocA}, + Data: allocA, }, ctx) - prepper.PreTransaction(executor.State[*substate.Substate]{ + prepper.PreTransaction(executor.State[txcontext.TxContext]{ Block: 7, - Data: &substate.Substate{InputAlloc: allocB}, + Data: allocB, }, ctx) } @@ -42,7 +44,7 @@ func TestStatePrepper_DoesNotCrashOnMissingStateOrSubstate(t *testing.T) { ctx := &executor.Context{State: db} prepper := MakeStateDbPrepper() - prepper.PreTransaction(executor.State[*substate.Substate]{Block: 5}, nil) // misses both - prepper.PreTransaction(executor.State[*substate.Substate]{Block: 5}, ctx) // misses the substate - prepper.PreTransaction(executor.State[*substate.Substate]{Block: 5, Data: &substate.Substate{}}, nil) // misses the state + prepper.PreTransaction(executor.State[txcontext.TxContext]{Block: 5}, nil) // misses both + prepper.PreTransaction(executor.State[txcontext.TxContext]{Block: 5}, ctx) // misses the data + prepper.PreTransaction(executor.State[txcontext.TxContext]{Block: 5, Data: substatecontext.NewTxContext(&substate.Substate{})}, nil) // misses the state } diff --git a/executor/extension/statedb/temporary_archive_prepper.go b/executor/extension/statedb/temporary_archive_prepper.go index 4f852cbec..5e36c6628 100644 --- a/executor/extension/statedb/temporary_archive_prepper.go +++ b/executor/extension/statedb/temporary_archive_prepper.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) -// MakeTemporaryArchivePrepper creates an extension for retrieving temporary archive before every transaction. +// MakeTemporaryArchivePrepper creates an extension for retrieving temporary archive before every txcontext. // Archive is assigned to context.Archive. Archive is released after transaction. func MakeTemporaryArchivePrepper() executor.Extension[*rpc.RequestAndResults] { return &temporaryArchivePrepper{} diff --git a/executor/extension/statedb/temporary_state_prepper.go b/executor/extension/statedb/temporary_state_prepper.go index 90b307c83..9808d5a9b 100644 --- a/executor/extension/statedb/temporary_state_prepper.go +++ b/executor/extension/statedb/temporary_state_prepper.go @@ -6,14 +6,15 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/executor/extension" statedb "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" ) // MakeTemporaryStatePrepper creates an executor.Extension which Makes a fresh StateDb -// after each transaction. Default is offTheChainStateDb. +// after each txcontext. Default is offTheChainStateDb. // NOTE: inMemoryStateDb currently does not work for block 67m onwards. -func MakeTemporaryStatePrepper(cfg *utils.Config) executor.Extension[*substate.Substate] { +func MakeTemporaryStatePrepper(cfg *utils.Config) executor.Extension[txcontext.TxContext] { switch cfg.DbImpl { case "in-memory", "memory": return temporaryInMemoryStatePrepper{} @@ -31,28 +32,29 @@ func MakeTemporaryStatePrepper(cfg *utils.Config) executor.Extension[*substate.S // temporaryInMemoryStatePrepper is an extension that introduces a fresh in-memory // StateDB instance before each transaction execution. type temporaryInMemoryStatePrepper struct { - extension.NilExtension[*substate.Substate] + extension.NilExtension[txcontext.TxContext] } // PreTransaction creates new fresh StateDb -func (temporaryInMemoryStatePrepper) PreTransaction(state executor.State[*substate.Substate], ctx *executor.Context) error { - ctx.State = statedb.MakeInMemoryStateDB(&state.Data.InputAlloc, uint64(state.Block)) +func (temporaryInMemoryStatePrepper) PreTransaction(state executor.State[txcontext.TxContext], ctx *executor.Context) error { + alloc := state.Data.GetInputState() + ctx.State = statedb.MakeInMemoryStateDB(alloc, uint64(state.Block)) return nil } // temporaryOffTheChainStatePrepper is an extension that introduces a fresh offTheChain // StateDB instance before each transaction execution. type temporaryOffTheChainStatePrepper struct { - extension.NilExtension[*substate.Substate] + extension.NilExtension[txcontext.TxContext] cfg *utils.Config } // PreTransaction creates new fresh StateDb -func (p *temporaryOffTheChainStatePrepper) PreTransaction(state executor.State[*substate.Substate], ctx *executor.Context) error { +func (p *temporaryOffTheChainStatePrepper) PreTransaction(state executor.State[txcontext.TxContext], ctx *executor.Context) error { var err error if p.cfg == nil { return fmt.Errorf("temporaryOffTheChainStatePrepper: cfg is nil") } - ctx.State, err = statedb.MakeOffTheChainStateDB(state.Data.InputAlloc, uint64(state.Block), statedb.NewChainConduit(p.cfg.ChainID == utils.EthereumChainID, utils.GetChainConfig(utils.EthereumChainID))) + ctx.State, err = statedb.MakeOffTheChainStateDB(state.Data.GetInputState(), uint64(state.Block), statedb.NewChainConduit(p.cfg.ChainID == utils.EthereumChainID, utils.GetChainConfig(utils.EthereumChainID))) return err } diff --git a/executor/extension/tracker/progress_tracker.go b/executor/extension/tracker/progress_tracker.go index 967b5b37e..8508008aa 100644 --- a/executor/extension/tracker/progress_tracker.go +++ b/executor/extension/tracker/progress_tracker.go @@ -8,8 +8,8 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/executor/extension" "github.com/Fantom-foundation/Aida/logger" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" ) const ( @@ -19,9 +19,9 @@ const ( // MakeProgressTracker creates a progressTracker that depends on the // PostBlock event and is only useful as part of a sequential evaluation. -func MakeProgressTracker(cfg *utils.Config, reportFrequency int) executor.Extension[*substate.Substate] { +func MakeProgressTracker(cfg *utils.Config, reportFrequency int) executor.Extension[txcontext.TxContext] { if !cfg.TrackProgress { - return extension.NilExtension[*substate.Substate]{} + return extension.NilExtension[txcontext.TxContext]{} } if reportFrequency == 0 { @@ -43,7 +43,7 @@ func makeProgressTracker(cfg *utils.Config, reportFrequency int, log logger.Logg // progressTracker logs progress every XXX blocks depending on reportFrequency. // Default is 100_000 blocks. This is mainly used for gathering information about process. type progressTracker struct { - extension.NilExtension[*substate.Substate] + extension.NilExtension[txcontext.TxContext] cfg *utils.Config log logger.Logger reportFrequency int @@ -60,7 +60,7 @@ type processInfo struct { gas uint64 } -func (t *progressTracker) PreRun(state executor.State[*substate.Substate], _ *executor.Context) error { +func (t *progressTracker) PreRun(state executor.State[txcontext.TxContext], _ *executor.Context) error { now := time.Now() t.startOfRun = now t.startOfLastInterval = now @@ -68,18 +68,18 @@ func (t *progressTracker) PreRun(state executor.State[*substate.Substate], _ *ex } // PostTransaction increments number of transactions and saves gas used in last substate. -func (t *progressTracker) PostTransaction(state executor.State[*substate.Substate], _ *executor.Context) error { +func (t *progressTracker) PostTransaction(state executor.State[txcontext.TxContext], _ *executor.Context) error { t.lock.Lock() defer t.lock.Unlock() t.overallInfo.numTransactions++ - t.overallInfo.gas += state.Data.Result.GasUsed + t.overallInfo.gas += state.Data.GetReceipt().GetGasUsed() return nil } // PostBlock registers the completed block and may trigger the logging of an update. -func (t *progressTracker) PostBlock(state executor.State[*substate.Substate], ctx *executor.Context) error { +func (t *progressTracker) PostBlock(state executor.State[txcontext.TxContext], ctx *executor.Context) error { boundary := state.Block - (state.Block % t.reportFrequency) if state.Block-t.lastReportedBlock < t.reportFrequency { diff --git a/executor/extension/tracker/progress_tracker_test.go b/executor/extension/tracker/progress_tracker_test.go index baf6d09a2..313ae866b 100644 --- a/executor/extension/tracker/progress_tracker_test.go +++ b/executor/extension/tracker/progress_tracker_test.go @@ -11,6 +11,8 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension" "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "go.uber.org/mock/gomock" @@ -22,7 +24,7 @@ func TestProgressTrackerExtension_NoLoggerIsCreatedIfDisabled(t *testing.T) { cfg := &utils.Config{} cfg.TrackProgress = false ext := MakeProgressTracker(cfg, testStateDbInfoFrequency) - if _, ok := ext.(extension.NilExtension[*substate.Substate]); !ok { + if _, ok := ext.(extension.NilExtension[txcontext.TxContext]); !ok { t.Errorf("Logger is enabled although not set in configuration") } @@ -45,12 +47,12 @@ func TestProgressTrackerExtension_LoggingHappens(t *testing.T) { ctx := &executor.Context{State: db, StateDbPath: dummyStateDbPath} - s := &substate.Substate{ + s := substatecontext.NewTxContext(&substate.Substate{ Result: &substate.SubstateResult{ Status: 0, GasUsed: 100, }, - } + }) gomock.InOrder( db.EXPECT().GetMemoryUsage().Return(&state.MemoryUsage{UsedBytes: 1234}), @@ -75,12 +77,12 @@ func TestProgressTrackerExtension_LoggingHappens(t *testing.T) { ), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) // first processed block - ext.PostTransaction(executor.State[*substate.Substate]{Data: s}, ctx) - ext.PostTransaction(executor.State[*substate.Substate]{Data: s}, ctx) - ext.PostBlock(executor.State[*substate.Substate]{ + ext.PostTransaction(executor.State[txcontext.TxContext]{Data: s}, ctx) + ext.PostTransaction(executor.State[txcontext.TxContext]{Data: s}, ctx) + ext.PostBlock(executor.State[txcontext.TxContext]{ Block: 5, Data: s, }, ctx) @@ -88,17 +90,17 @@ func TestProgressTrackerExtension_LoggingHappens(t *testing.T) { time.Sleep(500 * time.Millisecond) // second processed block - ext.PostTransaction(executor.State[*substate.Substate]{Data: s}, ctx) - ext.PostTransaction(executor.State[*substate.Substate]{Data: s}, ctx) - ext.PostBlock(executor.State[*substate.Substate]{ + ext.PostTransaction(executor.State[txcontext.TxContext]{Data: s}, ctx) + ext.PostTransaction(executor.State[txcontext.TxContext]{Data: s}, ctx) + ext.PostBlock(executor.State[txcontext.TxContext]{ Block: 6, Data: s, }, ctx) time.Sleep(500 * time.Millisecond) - ext.PostTransaction(executor.State[*substate.Substate]{Data: s}, ctx) - ext.PostBlock(executor.State[*substate.Substate]{ + ext.PostTransaction(executor.State[txcontext.TxContext]{Data: s}, ctx) + ext.PostBlock(executor.State[txcontext.TxContext]{ Block: 8, Data: s, }, ctx) @@ -116,30 +118,30 @@ func TestProgressTrackerExtension_FirstLoggingIsIgnored(t *testing.T) { ctx := &executor.Context{State: db} - s := &substate.Substate{ + s := substatecontext.NewTxContext(&substate.Substate{ Result: &substate.SubstateResult{ Status: 0, GasUsed: 10, }, - } + }) - ext.PreRun(executor.State[*substate.Substate]{ + ext.PreRun(executor.State[txcontext.TxContext]{ Block: 4, Transaction: 0, Data: s, }, ctx) - ext.PostTransaction(executor.State[*substate.Substate]{ + ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 4, Transaction: 0, Data: s, }, ctx) - ext.PostTransaction(executor.State[*substate.Substate]{ + ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 4, Transaction: 1, Data: s, }, ctx) - ext.PostBlock(executor.State[*substate.Substate]{ + ext.PostBlock(executor.State[txcontext.TxContext]{ Block: 5, Transaction: 0, Data: s, diff --git a/executor/extension/validator/state_db_validator.go b/executor/extension/validator/state_db_validator.go index 577ce9a80..9a667ab94 100644 --- a/executor/extension/validator/state_db_validator.go +++ b/executor/extension/validator/state_db_validator.go @@ -10,16 +10,16 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension" "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" - substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) // MakeLiveDbValidator creates an extension which validates LIVE StateDb -func MakeLiveDbValidator(cfg *utils.Config) executor.Extension[*substate.Substate] { +func MakeLiveDbValidator(cfg *utils.Config) executor.Extension[txcontext.TxContext] { if !cfg.ValidateTxState { - return extension.NilExtension[*substate.Substate]{} + return extension.NilExtension[txcontext.TxContext]{} } log := logger.NewLogger(cfg.LogLevel, "Tx-Verifier") @@ -38,8 +38,8 @@ type liveDbTxValidator struct { } // PreTransaction validates InputAlloc in given substate -func (v *liveDbTxValidator) PreTransaction(state executor.State[*substate.Substate], ctx *executor.Context) error { - err := v.validateSubstateAlloc(ctx.State, state.Data.InputAlloc) +func (v *liveDbTxValidator) PreTransaction(state executor.State[txcontext.TxContext], ctx *executor.Context) error { + err := v.validateSubstateAlloc(ctx.State, state.Data.GetInputState()) if err == nil { return nil } @@ -54,8 +54,8 @@ func (v *liveDbTxValidator) PreTransaction(state executor.State[*substate.Substa } // PostTransaction validates OutputAlloc in given substate -func (v *liveDbTxValidator) PostTransaction(state executor.State[*substate.Substate], ctx *executor.Context) error { - err := v.validateSubstateAlloc(ctx.State, state.Data.OutputAlloc) +func (v *liveDbTxValidator) PostTransaction(state executor.State[txcontext.TxContext], ctx *executor.Context) error { + err := v.validateSubstateAlloc(ctx.State, state.Data.GetOutputState()) if err == nil { return nil } @@ -70,9 +70,9 @@ func (v *liveDbTxValidator) PostTransaction(state executor.State[*substate.Subst } // MakeArchiveDbValidator creates an extension which validates ARCHIVE StateDb -func MakeArchiveDbValidator(cfg *utils.Config) executor.Extension[*substate.Substate] { +func MakeArchiveDbValidator(cfg *utils.Config) executor.Extension[txcontext.TxContext] { if !cfg.ValidateTxState { - return extension.NilExtension[*substate.Substate]{} + return extension.NilExtension[txcontext.TxContext]{} } log := logger.NewLogger(cfg.LogLevel, "Tx-Verifier") @@ -91,8 +91,8 @@ type archiveDbValidator struct { } // PreTransaction validates InputAlloc in given substate -func (v *archiveDbValidator) PreTransaction(state executor.State[*substate.Substate], ctx *executor.Context) error { - err := v.validateSubstateAlloc(ctx.Archive, state.Data.InputAlloc) +func (v *archiveDbValidator) PreTransaction(state executor.State[txcontext.TxContext], ctx *executor.Context) error { + err := v.validateSubstateAlloc(ctx.Archive, state.Data.GetInputState()) if err == nil { return nil } @@ -107,8 +107,8 @@ func (v *archiveDbValidator) PreTransaction(state executor.State[*substate.Subst } // PostTransaction validates VmAlloc -func (v *archiveDbValidator) PostTransaction(state executor.State[*substate.Substate], ctx *executor.Context) error { - err := v.validateSubstateAlloc(ctx.Archive, state.Data.OutputAlloc) +func (v *archiveDbValidator) PostTransaction(state executor.State[txcontext.TxContext], ctx *executor.Context) error { + err := v.validateSubstateAlloc(ctx.Archive, state.Data.GetOutputState()) if err == nil { return nil } @@ -134,14 +134,14 @@ func makeStateDbValidator(cfg *utils.Config, log logger.Logger) *stateDbValidato } type stateDbValidator struct { - extension.NilExtension[*substate.Substate] + extension.NilExtension[txcontext.TxContext] cfg *utils.Config log logger.Logger numberOfErrors *atomic.Int32 } // PreRun informs the user that stateDbValidator is enabled and that they should expect slower processing speed. -func (v *stateDbValidator) PreRun(executor.State[*substate.Substate], *executor.Context) error { +func (v *stateDbValidator) PreRun(executor.State[txcontext.TxContext], *executor.Context) error { v.log.Warning("Transaction verification is enabled, this may slow down the block processing.") if v.cfg.ContinueOnFailure { @@ -178,7 +178,7 @@ func (v *stateDbValidator) isErrFatal(err error, ch chan error) bool { // validateSubstateAlloc compares states of accounts in stateDB to an expected set of states. // If fullState mode, check if expected state is contained in stateDB. // If partialState mode, check for equality of sets. -func (v *stateDbValidator) validateSubstateAlloc(db state.VmStateDB, expectedAlloc substate.SubstateAlloc) error { +func (v *stateDbValidator) validateSubstateAlloc(db state.VmStateDB, expectedAlloc txcontext.WorldState) error { var err error switch v.cfg.StateValidationMode { case utils.SubsetCheck: @@ -188,7 +188,7 @@ func (v *stateDbValidator) validateSubstateAlloc(db state.VmStateDB, expectedAll isEqual := expectedAlloc.Equal(vmAlloc) if !isEqual { err = fmt.Errorf("inconsistent output: alloc") - v.printAllocationDiffSummary(&expectedAlloc, &vmAlloc) + v.printAllocationDiffSummary(expectedAlloc, vmAlloc) return err } @@ -238,111 +238,115 @@ func (v *stateDbValidator) printLogDiffSummary(label string, want, have *types.L } // printAllocationDiffSummary compares atrributes and existence of accounts and reports differences if any. -func (v *stateDbValidator) printAllocationDiffSummary(want, have *substate.SubstateAlloc) { - printIfDifferent("substate alloc size", len(*want), len(*have), v.log) - for key := range *want { - _, present := (*have)[key] - if !present { - v.log.Errorf("\tmissing key=%v\n", key) +func (v *stateDbValidator) printAllocationDiffSummary(want, have txcontext.WorldState) { + printIfDifferent("substate alloc size", want.Len(), have.Len(), v.log) + want.ForEachAccount(func(addr common.Address, acc txcontext.Account) { + if have.Get(addr) == nil { + v.log.Errorf("\tmissing address=%v\n", addr) } - } + }) - for key := range *have { - _, present := (*want)[key] - if !present { - v.log.Errorf("\textra key=%v\n", key) + have.ForEachAccount(func(addr common.Address, acc txcontext.Account) { + if want.Get(addr) == nil { + v.log.Errorf("\textra address=%v\n", addr) } - } + }) + + have.ForEachAccount(func(addr common.Address, acc txcontext.Account) { + wantAcc := want.Get(addr) + v.printAccountDiffSummary(fmt.Sprintf("key=%v:", addr), wantAcc, acc) + }) - for key, is := range *have { - should, present := (*want)[key] - if present { - v.printAccountDiffSummary(fmt.Sprintf("key=%v:", key), should, is) - } - } } // PrintAccountDiffSummary compares attributes of two accounts and reports differences if any. -func (v *stateDbValidator) printAccountDiffSummary(label string, want, have *substate.SubstateAccount) { - printIfDifferent(fmt.Sprintf("%s.Nonce", label), want.Nonce, have.Nonce, v.log) - v.printIfDifferentBigInt(fmt.Sprintf("%s.Balance", label), want.Balance, have.Balance) - v.printIfDifferentBytes(fmt.Sprintf("%s.Code", label), want.Code, have.Code) - - printIfDifferent(fmt.Sprintf("len(%s.Storage)", label), len(want.Storage), len(have.Storage), v.log) - for key, val := range want.Storage { - _, present := have.Storage[key] - if !present && (val != common.Hash{}) { - v.log.Errorf("\t%s.Storage misses key %v val %v\n", label, key, val) - } - } +func (v *stateDbValidator) printAccountDiffSummary(label string, want, have txcontext.Account) { + printIfDifferent(fmt.Sprintf("%s.Nonce", label), want.GetNonce(), have.GetNonce(), v.log) + v.printIfDifferentBigInt(fmt.Sprintf("%s.Balance", label), want.GetBalance(), have.GetBalance()) + v.printIfDifferentBytes(fmt.Sprintf("%s.Code", label), want.GetCode(), have.GetCode()) + + printIfDifferent(fmt.Sprintf("len(%s.Storage)", label), want.GetStorageSize(), have.GetStorageSize(), v.log) - for key := range have.Storage { - _, present := want.Storage[key] - if !present { - v.log.Errorf("\t%s.Storage has extra key %v\n", label, key) + want.ForEachStorage(func(keyHash common.Hash, valueHash common.Hash) { + haveValueHash := have.GetStorageAt(keyHash) + if haveValueHash != valueHash { + v.log.Errorf("\t%s.Storage misses key %v val %v\n", label, keyHash, valueHash) } - } + }) - for key, is := range have.Storage { - should, present := want.Storage[key] - if present { - printIfDifferent(fmt.Sprintf("%s.Storage[%v]", label, key), should, is, v.log) + have.ForEachStorage(func(keyHash common.Hash, valueHash common.Hash) { + wantValueHash := want.GetStorageAt(keyHash) + if wantValueHash != valueHash { + v.log.Errorf("\t%s.Storage has extra key %v\n", label, keyHash) } - } + }) + + have.ForEachStorage(func(keyHash common.Hash, valueHash common.Hash) { + wantValueHash := want.GetStorageAt(keyHash) + printIfDifferent(fmt.Sprintf("%s.Storage[%v]", label, keyHash), wantValueHash, valueHash, v.log) + }) + } // doSubsetValidation validates whether the given alloc is contained in the db object. // NB: We can only check what must be in the db (but cannot check whether db stores more). -func doSubsetValidation(alloc substate.SubstateAlloc, db state.VmStateDB, updateOnFail bool) error { +func doSubsetValidation(alloc txcontext.WorldState, db state.VmStateDB, updateOnFail bool) error { var err string - for addr, account := range alloc { + + alloc.ForEachAccount(func(addr common.Address, acc txcontext.Account) { if !db.Exist(addr) { err += fmt.Sprintf(" Account %v does not exist\n", addr.Hex()) if updateOnFail { db.CreateAccount(addr) } } - if balance := db.GetBalance(addr); account.Balance.Cmp(balance) != 0 { + accBalance := acc.GetBalance() + + if balance := db.GetBalance(addr); accBalance.Cmp(balance) != 0 { err += fmt.Sprintf(" Failed to validate balance for account %v\n"+ " have %v\n"+ " want %v\n", - addr.Hex(), balance, account.Balance) + addr.Hex(), balance, accBalance) if updateOnFail { db.SubBalance(addr, balance) - db.AddBalance(addr, account.Balance) + db.AddBalance(addr, accBalance) } } - if nonce := db.GetNonce(addr); nonce != account.Nonce { + if nonce := db.GetNonce(addr); nonce != acc.GetNonce() { err += fmt.Sprintf(" Failed to validate nonce for account %v\n"+ " have %v\n"+ " want %v\n", - addr.Hex(), nonce, account.Nonce) + addr.Hex(), nonce, acc.GetNonce()) if updateOnFail { - db.SetNonce(addr, account.Nonce) + db.SetNonce(addr, acc.GetNonce()) } } - if code := db.GetCode(addr); bytes.Compare(code, account.Code) != 0 { + if code := db.GetCode(addr); bytes.Compare(code, acc.GetCode()) != 0 { err += fmt.Sprintf(" Failed to validate code for account %v\n"+ " have len %v\n"+ " want len %v\n", - addr.Hex(), len(code), len(account.Code)) + addr.Hex(), len(code), len(acc.GetCode())) if updateOnFail { - db.SetCode(addr, account.Code) + db.SetCode(addr, acc.GetCode()) } } - for key, value := range account.Storage { - if db.GetState(addr, key) != value { + + // validate Storage + acc.ForEachStorage(func(keyHash common.Hash, valueHash common.Hash) { + if db.GetState(addr, keyHash) != valueHash { err += fmt.Sprintf(" Failed to validate storage for account %v, key %v\n"+ " have %v\n"+ " want %v\n", - addr.Hex(), key.Hex(), db.GetState(addr, key).Hex(), value.Hex()) + addr.Hex(), keyHash.Hex(), db.GetState(addr, keyHash).Hex(), valueHash.Hex()) if updateOnFail { - db.SetState(addr, key, value) + db.SetState(addr, keyHash, valueHash) } } - } - } + }) + + }) + if len(err) > 0 { return fmt.Errorf(err) } diff --git a/executor/extension/validator/state_db_validator_test.go b/executor/extension/validator/state_db_validator_test.go index e941f61d4..d6e5328a7 100644 --- a/executor/extension/validator/state_db_validator_test.go +++ b/executor/extension/validator/state_db_validator_test.go @@ -11,6 +11,8 @@ import ( "github.com/Fantom-foundation/Aida/executor/extension" "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" @@ -39,7 +41,7 @@ func TestLiveTxValidator_NoValidatorIsCreatedIfDisabled(t *testing.T) { ext := MakeLiveDbValidator(cfg) - if _, ok := ext.(extension.NilExtension[*substate.Substate]); !ok { + if _, ok := ext.(extension.NilExtension[txcontext.TxContext]); !ok { t.Errorf("Validator is enabled although not set in configuration") } } @@ -54,7 +56,7 @@ func TestLiveTxValidator_ValidatorIsEnabled(t *testing.T) { ext := makeLiveDbValidator(cfg, log) log.EXPECT().Warning(gomock.Any()) - ext.PreRun(executor.State[*substate.Substate]{}, nil) + ext.PreRun(executor.State[txcontext.TxContext]{}, nil) } func TestLiveTxValidator_ValidatorDoesNotFailWithEmptySubstate(t *testing.T) { @@ -69,12 +71,12 @@ func TestLiveTxValidator_ValidatorDoesNotFailWithEmptySubstate(t *testing.T) { ext := makeLiveDbValidator(cfg, log) log.EXPECT().Warning(gomock.Any()) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PostTransaction(executor.State[*substate.Substate]{ + err := ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, - Data: &substate.Substate{}, + Data: substatecontext.NewTxContext(&substate.Substate{}), }, ctx) if err != nil { @@ -102,9 +104,9 @@ func TestLiveTxValidator_SingleErrorInPreTransactionDoesNotEndProgramWithContinu db.EXPECT().GetCode(common.Address{0}).Return([]byte{0}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PreTransaction(executor.State[*substate.Substate]{ + err := ext.PreTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -134,9 +136,9 @@ func TestLiveTxValidator_SingleErrorInPreTransactionReturnsErrorWithNoContinueOn db.EXPECT().GetCode(common.Address{0}).Return([]byte{0}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PreTransaction(executor.State[*substate.Substate]{ + err := ext.PreTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -175,9 +177,9 @@ func TestLiveTxValidator_SingleErrorInPostTransactionReturnsErrorWithNoContinueO db.EXPECT().GetCode(common.Address{0}).Return([]byte{0}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PostTransaction(executor.State[*substate.Substate]{ + err := ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -211,14 +213,14 @@ func TestLiveTxValidator_SingleErrorInPostTransactionReturnsErrorWithNoContinueO gomock.InOrder( log.EXPECT().Warning(gomock.Any()), - db.EXPECT().GetSubstatePostAlloc().Return(substate.SubstateAlloc{}), + db.EXPECT().GetSubstatePostAlloc().Return(substatecontext.NewWorldState(substate.SubstateAlloc{})), log.EXPECT().Errorf("Different %s:\nwant: %v\nhave: %v\n", "substate alloc size", 1, 0), - log.EXPECT().Errorf("\tmissing key=%v\n", common.Address{0}), + log.EXPECT().Errorf("\tmissing address=%v\n", common.Address{0}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PostTransaction(executor.State[*substate.Substate]{ + err := ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -266,9 +268,9 @@ func TestLiveTxValidator_TwoErrorsDoNotReturnAnErrorWhenContinueOnFailureIsEnabl db.EXPECT().GetCode(common.Address{0}).Return([]byte{0}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PreTransaction(executor.State[*substate.Substate]{ + err := ext.PreTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -278,7 +280,7 @@ func TestLiveTxValidator_TwoErrorsDoNotReturnAnErrorWhenContinueOnFailureIsEnabl t.Errorf("PreTransaction must not return an error because continue on failure is true!") } - err = ext.PostTransaction(executor.State[*substate.Substate]{ + err = ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -320,9 +322,9 @@ func TestLiveTxValidator_TwoErrorsDoReturnErrorOnEventWhenContinueOnFailureIsEna db.EXPECT().GetCode(common.Address{0}).Return([]byte{0}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PreTransaction(executor.State[*substate.Substate]{ + err := ext.PreTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -332,7 +334,7 @@ func TestLiveTxValidator_TwoErrorsDoReturnErrorOnEventWhenContinueOnFailureIsEna t.Errorf("PreTransaction must not return an error because continue on failure is true, got %v", err) } - err = ext.PostTransaction(executor.State[*substate.Substate]{ + err = ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -355,14 +357,16 @@ func TestLiveTxValidator_PreTransactionDoesNotFailWithIncorrectOutput(t *testing ext := MakeLiveDbValidator(cfg) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PreTransaction(executor.State[*substate.Substate]{ + alloc := &substate.Substate{ + OutputAlloc: getIncorrectSubstateAlloc(), + } + + err := ext.PreTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, - Data: &substate.Substate{ - OutputAlloc: getIncorrectSubstateAlloc(), - }, + Data: substatecontext.NewTxContext(alloc), }, ctx) if err != nil { @@ -382,14 +386,16 @@ func TestLiveTxValidator_PostTransactionDoesNotFailWithIncorrectInput(t *testing ext := MakeLiveDbValidator(cfg) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) + + alloc := &substate.Substate{ + InputAlloc: getIncorrectSubstateAlloc(), + } - err := ext.PostTransaction(executor.State[*substate.Substate]{ + err := ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, - Data: &substate.Substate{ - InputAlloc: getIncorrectSubstateAlloc(), - }, + Data: substatecontext.NewTxContext(alloc), }, ctx) if err != nil { @@ -403,7 +409,7 @@ func TestArchiveTxValidator_NoValidatorIsCreatedIfDisabled(t *testing.T) { ext := MakeArchiveDbValidator(cfg) - if _, ok := ext.(extension.NilExtension[*substate.Substate]); !ok { + if _, ok := ext.(extension.NilExtension[txcontext.TxContext]); !ok { t.Errorf("Validator is enabled although not set in configuration") } } @@ -418,7 +424,7 @@ func TestArchiveTxValidator_ValidatorIsEnabled(t *testing.T) { ext := makeArchiveDbValidator(cfg, log) log.EXPECT().Warning(gomock.Any()) - ext.PreRun(executor.State[*substate.Substate]{}, nil) + ext.PreRun(executor.State[txcontext.TxContext]{}, nil) } func TestArchiveTxValidator_ValidatorDoesNotFailWithEmptySubstate(t *testing.T) { @@ -433,12 +439,12 @@ func TestArchiveTxValidator_ValidatorDoesNotFailWithEmptySubstate(t *testing.T) ext := makeArchiveDbValidator(cfg, log) log.EXPECT().Warning(gomock.Any()) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PostTransaction(executor.State[*substate.Substate]{ + err := ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, - Data: &substate.Substate{}, + Data: substatecontext.NewTxContext(&substate.Substate{}), }, ctx) if err != nil { @@ -466,9 +472,9 @@ func TestArchiveTxValidator_SingleErrorInPreTransactionDoesNotEndProgramWithCont db.EXPECT().GetCode(common.Address{0}).Return([]byte{0}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PreTransaction(executor.State[*substate.Substate]{ + err := ext.PreTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -498,9 +504,9 @@ func TestArchiveTxValidator_SingleErrorInPreTransactionReturnsErrorWithNoContinu db.EXPECT().GetCode(common.Address{0}).Return([]byte{0}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PreTransaction(executor.State[*substate.Substate]{ + err := ext.PreTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -539,9 +545,9 @@ func TestArchiveTxValidator_SingleErrorInPostTransactionReturnsErrorWithNoContin db.EXPECT().GetCode(common.Address{0}).Return([]byte{0}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PostTransaction(executor.State[*substate.Substate]{ + err := ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -572,11 +578,11 @@ func TestArchiveTxValidator_SingleErrorInPostTransactionReturnsErrorWithNoContin ext := MakeArchiveDbValidator(cfg) - db.EXPECT().GetSubstatePostAlloc().Return(substate.SubstateAlloc{}) + db.EXPECT().GetSubstatePostAlloc().Return(substatecontext.NewWorldState(substate.SubstateAlloc{})) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PostTransaction(executor.State[*substate.Substate]{ + err := ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -624,9 +630,9 @@ func TestArchiveTxValidator_TwoErrorsDoNotReturnAnErrorWhenContinueOnFailureIsEn db.EXPECT().GetCode(common.Address{0}).Return([]byte{0}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PreTransaction(executor.State[*substate.Substate]{ + err := ext.PreTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -636,7 +642,7 @@ func TestArchiveTxValidator_TwoErrorsDoNotReturnAnErrorWhenContinueOnFailureIsEn t.Errorf("PreTransaction must not return an error because continue on failure is true!") } - err = ext.PostTransaction(executor.State[*substate.Substate]{ + err = ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -678,9 +684,9 @@ func TestArchiveTxValidator_TwoErrorsDoReturnErrorOnEventWhenContinueOnFailureIs db.EXPECT().GetCode(common.Address{0}).Return([]byte{0}), ) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PreTransaction(executor.State[*substate.Substate]{ + err := ext.PreTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -690,7 +696,7 @@ func TestArchiveTxValidator_TwoErrorsDoReturnErrorOnEventWhenContinueOnFailureIs t.Errorf("PreTransaction must not return an error because continue on failure is true, got %v", err) } - err = ext.PostTransaction(executor.State[*substate.Substate]{ + err = ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, Data: getIncorrectTestSubstateAlloc(), @@ -713,14 +719,14 @@ func TestArchiveTxValidator_PreTransactionDoesNotFailWithIncorrectOutput(t *test ext := MakeArchiveDbValidator(cfg) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PreTransaction(executor.State[*substate.Substate]{ + err := ext.PreTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, - Data: &substate.Substate{ + Data: substatecontext.NewTxContext(&substate.Substate{ OutputAlloc: getIncorrectSubstateAlloc(), - }, + }), }, ctx) if err != nil { @@ -740,14 +746,14 @@ func TestArchiveTxValidator_PostTransactionDoesNotFailWithIncorrectInput(t *test ext := MakeLiveDbValidator(cfg) - ext.PreRun(executor.State[*substate.Substate]{}, ctx) + ext.PreRun(executor.State[txcontext.TxContext]{}, ctx) - err := ext.PostTransaction(executor.State[*substate.Substate]{ + err := ext.PostTransaction(executor.State[txcontext.TxContext]{ Block: 1, Transaction: 1, - Data: &substate.Substate{ + Data: substatecontext.NewTxContext(&substate.Substate{ InputAlloc: getIncorrectSubstateAlloc(), - }, + }), }, ctx) if err != nil { @@ -776,7 +782,8 @@ func TestValidateStateDb_ValidationDoesNotFail(t *testing.T) { }(sDB) // Generating randomized world state - ws, _ := utils.MakeWorldState(t) + alloc, _ := utils.MakeWorldState(t) + ws := substatecontext.NewWorldState(alloc) log := logger.NewLogger("INFO", "TestStateDb") @@ -823,42 +830,46 @@ func TestValidateStateDb_ValidationDoesNotFailWithPriming(t *testing.T) { // Create new prime context pc := utils.NewPrimeContext(cfg, sDB, log) // Priming state DB with given world state - pc.PrimeStateDB(ws, sDB) + pc.PrimeStateDB(substatecontext.NewWorldState(ws), sDB) // create new random address addr := common.BytesToAddress(utils.MakeRandomByteSlice(t, 40)) // create new account - ws[addr] = &substate.SubstateAccount{ + subAcc := &substate.SubstateAccount{ Nonce: uint64(utils.GetRandom(1, 1000*5000)), Balance: big.NewInt(int64(utils.GetRandom(1, 1000*5000))), Storage: utils.MakeAccountStorage(t), Code: utils.MakeRandomByteSlice(t, 2048), } + ws[addr] = subAcc + // Call for state DB validation with update enabled and subsequent checks if the update was made correctly - err = doSubsetValidation(ws, sDB, true) + err = doSubsetValidation(substatecontext.NewWorldState(ws), sDB, true) if err == nil { t.Fatalf("failed to throw errors while validating state DB: %v", err) } - if sDB.GetBalance(addr).Cmp(ws[addr].Balance) != 0 { - t.Fatalf("failed to prime account balance; Is: %v; Should be: %v", sDB.GetBalance(addr), ws[addr].Balance) + acc := ws[addr] + if sDB.GetBalance(addr).Cmp(acc.Balance) != 0 { + t.Fatalf("failed to prime account balance; Is: %v; Should be: %v", sDB.GetBalance(addr), acc.Balance) } - if sDB.GetNonce(addr) != ws[addr].Nonce { - t.Fatalf("failed to prime account nonce; Is: %v; Should be: %v", sDB.GetNonce(addr), ws[addr].Nonce) + if sDB.GetNonce(addr) != acc.Nonce { + t.Fatalf("failed to prime account nonce; Is: %v; Should be: %v", sDB.GetNonce(addr), acc.Nonce) } - if bytes.Compare(sDB.GetCode(addr), ws[addr].Code) != 0 { - t.Fatalf("failed to prime account code; Is: %v; Should be: %v", sDB.GetCode(addr), ws[addr].Code) + if bytes.Compare(sDB.GetCode(addr), acc.Code) != 0 { + t.Fatalf("failed to prime account code; Is: %v; Should be: %v", sDB.GetCode(addr), acc.Code) } - for sKey, sValue := range ws[addr].Storage { - if sDB.GetState(addr, sKey) != sValue { - t.Fatalf("failed to prime account storage; Is: %v; Should be: %v", sDB.GetState(addr, sKey), sValue) + for keyHash, valueHash := range acc.Storage { + if sDB.GetState(addr, keyHash) != valueHash { + t.Fatalf("failed to prime account storage; Is: %v; Should be: %v", sDB.GetState(addr, keyHash), valueHash) } } + }) } } @@ -866,13 +877,13 @@ func TestValidateStateDb_ValidationDoesNotFailWithPriming(t *testing.T) { // getIncorrectTestSubstateAlloc returns an error // Substate with incorrect InputAlloc and OutputAlloc. // This func is only used in testing. -func getIncorrectTestSubstateAlloc() *substate.Substate { +func getIncorrectTestSubstateAlloc() txcontext.TxContext { sub := &substate.Substate{ InputAlloc: getIncorrectSubstateAlloc(), OutputAlloc: getIncorrectSubstateAlloc(), } - return sub + return substatecontext.NewTxContext(sub) } func getIncorrectSubstateAlloc() substate.SubstateAlloc { diff --git a/executor/substate_processor.go b/executor/substate_processor.go index 68e41f63e..83531c198 100644 --- a/executor/substate_processor.go +++ b/executor/substate_processor.go @@ -7,6 +7,8 @@ import ( "sync/atomic" "github.com/Fantom-foundation/Aida/state" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/Fantom-foundation/go-opera/evmcore" @@ -28,7 +30,7 @@ type LiveDbProcessor struct { } // Process transaction inside state into given LIVE StateDb -func (p *LiveDbProcessor) Process(state State[*substate.Substate], ctx *Context) error { +func (p *LiveDbProcessor) Process(state State[txcontext.TxContext], ctx *Context) error { var err error err = p.ProcessTransaction(ctx.State, state.Block, state.Transaction, state.Data) @@ -54,7 +56,7 @@ type ArchiveDbProcessor struct { } // Process transaction inside state into given ARCHIVE StateDb -func (p *ArchiveDbProcessor) Process(state State[*substate.Substate], ctx *Context) error { +func (p *ArchiveDbProcessor) Process(state State[txcontext.TxContext], ctx *Context) error { var err error err = p.ProcessTransaction(ctx.Archive, state.Block, state.Transaction, state.Data) @@ -97,16 +99,16 @@ func (s *SubstateProcessor) isErrFatal() bool { return true } -func (s *SubstateProcessor) ProcessTransaction(db state.VmStateDB, block int, tx int, st *substate.Substate) error { +func (s *SubstateProcessor) ProcessTransaction(db state.VmStateDB, block int, tx int, st txcontext.TxContext) error { if tx >= utils.PseudoTx { - s.processPseudoTx(st.OutputAlloc, db) + s.processPseudoTx(st.GetOutputState(), db) return nil } return s.processRegularTx(db, block, tx, st) } // processRegularTx executes VM on a chosen storage system. -func (s *SubstateProcessor) processRegularTx(db state.VmStateDB, block int, tx int, st *substate.Substate) (finalError error) { +func (s *SubstateProcessor) processRegularTx(db state.VmStateDB, block int, tx int, st txcontext.TxContext) (finalError error) { db.BeginTransaction(uint32(tx)) defer db.EndTransaction() @@ -118,11 +120,11 @@ func (s *SubstateProcessor) processRegularTx(db state.VmStateDB, block int, tx i } // fantomTx processes a transaction in Fantom Opera EVM configuration -func (s *SubstateProcessor) fantomTx(db state.VmStateDB, block int, tx int, st *substate.Substate) (finalError error) { +func (s *SubstateProcessor) fantomTx(db state.VmStateDB, block int, tx int, st txcontext.TxContext) (finalError error) { var ( gaspool = new(evmcore.GasPool) txHash = common.HexToHash(fmt.Sprintf("0x%016d%016d", block, tx)) - inputEnv = st.Env + inputEnv = st.GetBlockEnvironment() hashError error validate = s.cfg.ValidateTxState ) @@ -137,8 +139,8 @@ func (s *SubstateProcessor) fantomTx(db state.VmStateDB, block int, tx int, st * chainConfig := utils.GetChainConfig(s.cfg.ChainID) // prepare tx - gaspool.AddGas(inputEnv.GasLimit) - msg := st.Message.AsMessage() + gaspool.AddGas(inputEnv.GetGasLimit()) + msg := st.GetMessage() db.Prepare(txHash, tx) blockCtx := prepareBlockCtx(inputEnv, &hashError) txCtx := evmcore.NewEVMTxContext(msg) @@ -174,7 +176,7 @@ func (s *SubstateProcessor) fantomTx(db state.VmStateDB, block int, tx int, st * contract = crypto.CreateAddress(evm.TxContext.Origin, msg.Nonce()) } vmResult := compileVMResult(logs, msgResult.UsedGas, msgResult.Failed(), contract) - if err = validateVMResult(vmResult, st.Result); err != nil { + if err = validateVMResult(vmResult, st.GetReceipt()); err != nil { finalError = errors.Join(finalError, err) } } @@ -182,13 +184,13 @@ func (s *SubstateProcessor) fantomTx(db state.VmStateDB, block int, tx int, st * } // ethereumTx processes a transaction in Ethereum EVM configuration -func (s *SubstateProcessor) ethereumTx(db state.VmStateDB, block int, tx int, st *substate.Substate) (finalError error) { +func (s *SubstateProcessor) ethereumTx(db state.VmStateDB, block int, tx int, st txcontext.TxContext) (finalError error) { var ( gaspool = new(core.GasPool) txHash = common.HexToHash(fmt.Sprintf("0x%016d%016d", block, tx)) - inputEnv = st.Env - hashError error + inputEnv = st.GetBlockEnvironment() validate = s.cfg.ValidateTxState + hashError error ) // create vm config @@ -201,8 +203,8 @@ func (s *SubstateProcessor) ethereumTx(db state.VmStateDB, block int, tx int, st chainConfig := utils.GetChainConfig(s.cfg.ChainID) // prepare tx - gaspool.AddGas(inputEnv.GasLimit) - msg := st.Message.AsMessage() + gaspool.AddGas(inputEnv.GetGasLimit()) + msg := st.GetMessage() db.Prepare(txHash, tx) blockCtx := prepareBlockCtx(inputEnv, &hashError) txCtx := core.NewEVMTxContext(msg) @@ -238,7 +240,7 @@ func (s *SubstateProcessor) ethereumTx(db state.VmStateDB, block int, tx int, st contract = crypto.CreateAddress(evm.TxContext.Origin, msg.Nonce()) } vmResult := compileVMResult(logs, msgResult.UsedGas, msgResult.Failed(), contract) - if err = validateVMResult(vmResult, st.Result); err != nil { + if err = validateVMResult(vmResult, st.GetReceipt()); err != nil { finalError = errors.Join(finalError, err) } } @@ -247,53 +249,52 @@ func (s *SubstateProcessor) ethereumTx(db state.VmStateDB, block int, tx int, st // processPseudoTx processes pseudo transactions in Lachesis by applying the change in db state. // The pseudo transactions includes Lachesis SFC, lachesis genesis and lachesis-opera transition. -func (s *SubstateProcessor) processPseudoTx(sa substate.SubstateAlloc, db state.VmStateDB) { +func (s *SubstateProcessor) processPseudoTx(ws txcontext.WorldState, db state.VmStateDB) { db.BeginTransaction(utils.PseudoTx) defer db.EndTransaction() - for addr, account := range sa { + ws.ForEachAccount(func(addr common.Address, acc txcontext.Account) { db.SubBalance(addr, db.GetBalance(addr)) - db.AddBalance(addr, account.Balance) - db.SetNonce(addr, account.Nonce) - db.SetCode(addr, account.Code) - for key, value := range account.Storage { - db.SetState(addr, key, value) - } - } + db.AddBalance(addr, acc.GetBalance()) + db.SetNonce(addr, acc.GetNonce()) + db.SetCode(addr, acc.GetCode()) + acc.ForEachStorage(func(keyHash common.Hash, valueHash common.Hash) { + db.SetState(addr, keyHash, valueHash) + }) + }) + } // prepareBlockCtx creates a block context for evm call from an environment of a substate. -func prepareBlockCtx(inputEnv *substate.SubstateEnv, hashError *error) *vm.BlockContext { +func prepareBlockCtx(inputEnv txcontext.BlockEnvironment, hashError *error) *vm.BlockContext { getHash := func(num uint64) common.Hash { - if inputEnv.BlockHashes == nil { - *hashError = fmt.Errorf("getHash(%d) invoked, no blockhashes provided", num) - return common.Hash{} - } - h, ok := inputEnv.BlockHashes[num] - if !ok { - *hashError = fmt.Errorf("getHash(%d) invoked, blockhash for that block not provided", num) + h := inputEnv.GetBlockHash(num) + if h == (common.Hash{}) { + *hashError = fmt.Errorf("hash for block %v was not found", num) } return h } + blockCtx := &vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, - Coinbase: inputEnv.Coinbase, - BlockNumber: new(big.Int).SetUint64(inputEnv.Number), - Time: new(big.Int).SetUint64(inputEnv.Timestamp), - Difficulty: inputEnv.Difficulty, - GasLimit: inputEnv.GasLimit, + Coinbase: inputEnv.GetCoinbase(), + BlockNumber: new(big.Int).SetUint64(inputEnv.GetNumber()), + Time: new(big.Int).SetUint64(inputEnv.GetTimestamp()), + Difficulty: inputEnv.GetDifficulty(), + GasLimit: inputEnv.GetGasLimit(), GetHash: getHash, } // If currentBaseFee is defined, add it to the vmContext. - if inputEnv.BaseFee != nil { - blockCtx.BaseFee = new(big.Int).Set(inputEnv.BaseFee) + baseFee := inputEnv.GetBaseFee() + if baseFee != nil { + blockCtx.BaseFee = new(big.Int).Set(baseFee) } return blockCtx } // compileVMResult creates a result of a transaction as SubstateResult struct. -func compileVMResult(logs []*types.Log, recieptUsedGas uint64, recieptFailed bool, contract common.Address) *substate.SubstateResult { +func compileVMResult(logs []*types.Log, recieptUsedGas uint64, recieptFailed bool, contract common.Address) txcontext.Receipt { vmResult := &substate.SubstateResult{ ContractAddress: contract, GasUsed: recieptUsedGas, @@ -305,11 +306,11 @@ func compileVMResult(logs []*types.Log, recieptUsedGas uint64, recieptFailed boo } else { vmResult.Status = types.ReceiptStatusSuccessful } - return vmResult + return substatecontext.NewReceipt(vmResult) } // validateVMResult compares the result of a transaction to an expected value. -func validateVMResult(vmResult, expectedResult *substate.SubstateResult) error { +func validateVMResult(vmResult, expectedResult txcontext.Receipt) error { if !expectedResult.Equal(vmResult) { return fmt.Errorf("inconsistent output\n"+ "\ngot:\n"+ @@ -324,16 +325,16 @@ func validateVMResult(vmResult, expectedResult *substate.SubstateResult) error { "\tlogs: %v\n"+ "\tcontract address: %v\n"+ "\tgas used: %v\n", - vmResult.Status, - vmResult.Bloom.Big().Uint64(), - vmResult.Logs, - vmResult.ContractAddress, - vmResult.GasUsed, - expectedResult.Status, - expectedResult.Bloom.Big().Uint64(), - expectedResult.Logs, - expectedResult.ContractAddress, - expectedResult.GasUsed, + vmResult.GetStatus(), + vmResult.GetBloom().Big().Uint64(), + vmResult.GetLogs(), + vmResult.GetContractAddress(), + vmResult.GetGasUsed(), + expectedResult.GetStatus(), + expectedResult.GetBloom().Big().Uint64(), + expectedResult.GetLogs(), + expectedResult.GetContractAddress(), + expectedResult.GetGasUsed(), ) } return nil diff --git a/executor/substate_processor_test.go b/executor/substate_processor_test.go index f3a220569..8767fbddd 100644 --- a/executor/substate_processor_test.go +++ b/executor/substate_processor_test.go @@ -6,6 +6,7 @@ import ( "strings" "testing" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" substate "github.com/Fantom-foundation/Substate" "github.com/Fantom-foundation/go-opera/evmcore" "github.com/ethereum/go-ethereum/common" @@ -13,12 +14,13 @@ import ( ) func newDummyResult(t *testing.T) *substate.SubstateResult { - return &substate.SubstateResult{ + r := &substate.SubstateResult{ Logs: []*types.Log{}, ContractAddress: common.HexToAddress("0x0000000000085a12481aEdb59eb3200332aCA541"), GasUsed: 1000000, Status: types.ReceiptStatusSuccessful, } + return r } // TestPrepareBlockCtx tests a creation of block context from substate environment. @@ -26,16 +28,11 @@ func TestPrepareBlockCtx(t *testing.T) { gaslimit := uint64(10000000) blocknum := uint64(4600000) basefee := big.NewInt(12345) - env := &substate.SubstateEnv{ - Difficulty: big.NewInt(1), - GasLimit: gaslimit, - Number: blocknum, - Timestamp: 1675961395, - BaseFee: basefee, - } + env := substatecontext.NewBlockEnvironment(&substate.SubstateEnv{Difficulty: big.NewInt(1), GasLimit: gaslimit, Number: blocknum, Timestamp: 1675961395, BaseFee: basefee}) + var hashError error // BlockHashes are nil, expect an error - blockCtx := prepareBlockCtx(env, nil) + blockCtx := prepareBlockCtx(env, &hashError) if blocknum != blockCtx.BlockNumber.Uint64() { t.Fatalf("Wrong block number") @@ -46,9 +43,12 @@ func TestPrepareBlockCtx(t *testing.T) { if basefee.Cmp(blockCtx.BaseFee) != 0 { t.Fatalf("Wrong base fee") } + if hashError != nil { + t.Fatalf("Hash error; %v", hashError) + } } -// TestCompileVMResult tests a construction of substate.Result from tx output +// TestCompileVMResult tests a construction of substate.Result from data output func TestCompileVMResult(t *testing.T) { var logs []*types.Log reciept_fail := &evmcore.ExecutionResult{UsedGas: 100, Err: fmt.Errorf("Test Error")} @@ -56,31 +56,31 @@ func TestCompileVMResult(t *testing.T) { sr := compileVMResult(logs, reciept_fail.UsedGas, reciept_fail.Failed(), contract) - if sr.ContractAddress != contract { + if sr.GetContractAddress() != contract { t.Fatalf("Wrong contract address") } - if sr.GasUsed != reciept_fail.UsedGas { + if sr.GetGasUsed() != reciept_fail.UsedGas { t.Fatalf("Wrong amount of gas used") } - if sr.Status != types.ReceiptStatusFailed { + if sr.GetStatus() != types.ReceiptStatusFailed { t.Fatalf("Wrong transaction status") } reciept_success := &evmcore.ExecutionResult{UsedGas: 100, Err: nil} sr = compileVMResult(logs, reciept_success.UsedGas, reciept_success.Failed(), contract) - if sr.Status != types.ReceiptStatusSuccessful { + if sr.GetStatus() != types.ReceiptStatusSuccessful { t.Fatalf("Wrong transaction status") } } -// TestValidateVMResult tests validatation of tx result. +// TestValidateVMResult tests validatation of data result. func TestValidateVMResult(t *testing.T) { expectedResult := newDummyResult(t) vmResult := newDummyResult(t) // test positive - err := validateVMResult(vmResult, expectedResult) + err := validateVMResult(substatecontext.NewReceipt(vmResult), substatecontext.NewReceipt(expectedResult)) if err != nil { t.Fatalf("Failed to validate VM output. %v", err) } @@ -88,14 +88,14 @@ func TestValidateVMResult(t *testing.T) { // test negative // mismatched contract vmResult.ContractAddress = common.HexToAddress("0x0000000000085a12481aEdb59eb3200332aCA542") - err = validateVMResult(vmResult, expectedResult) + err = validateVMResult(substatecontext.NewReceipt(vmResult), substatecontext.NewReceipt(expectedResult)) if err == nil { t.Fatalf("Failed to validate VM output. Expect contract address mismatch error.") } // mismatched gas used vmResult = newDummyResult(t) vmResult.GasUsed = 0 - err = validateVMResult(vmResult, expectedResult) + err = validateVMResult(substatecontext.NewReceipt(vmResult), substatecontext.NewReceipt(expectedResult)) if err == nil { t.Fatalf("Failed to validate VM output. Expect gas used mismatch error.") } @@ -103,7 +103,7 @@ func TestValidateVMResult(t *testing.T) { // mismatched gas used vmResult = newDummyResult(t) vmResult.Status = types.ReceiptStatusFailed - err = validateVMResult(vmResult, expectedResult) + err = validateVMResult(substatecontext.NewReceipt(vmResult), substatecontext.NewReceipt(expectedResult)) if err == nil { t.Fatalf("Failed to validate VM output. Expect staatus mismatch error.") } @@ -116,7 +116,10 @@ func TestValidateVMResult_ErrorIsInCorrectFormat(t *testing.T) { // change result so validation fails expectedResult.GasUsed = 15000 - err := validateVMResult(vmResult, expectedResult) + vmRes := substatecontext.NewReceipt(vmResult) + expRes := substatecontext.NewReceipt(expectedResult) + + err := validateVMResult(vmRes, expRes) if err == nil { t.Fatal("validation must fail") } @@ -134,16 +137,16 @@ func TestValidateVMResult_ErrorIsInCorrectFormat(t *testing.T) { "\tlogs: %v\n"+ "\tcontract address: %v\n"+ "\tgas used: %v\n", - vmResult.Status, - vmResult.Bloom.Big().Uint64(), - vmResult.Logs, - vmResult.ContractAddress, - vmResult.GasUsed, - expectedResult.Status, - expectedResult.Bloom.Big().Uint64(), - expectedResult.Logs, - expectedResult.ContractAddress, - expectedResult.GasUsed, + vmRes.GetStatus(), + vmRes.GetBloom().Big().Uint64(), + vmRes.GetLogs(), + vmRes.GetContractAddress(), + vmRes.GetGasUsed(), + expRes.GetStatus(), + expRes.GetBloom().Big().Uint64(), + expRes.GetLogs(), + expRes.GetContractAddress(), + expRes.GetGasUsed(), ) got := err.Error() diff --git a/executor/substate_provider.go b/executor/substate_provider.go index 323d1d572..70d85e656 100644 --- a/executor/substate_provider.go +++ b/executor/substate_provider.go @@ -5,6 +5,8 @@ package executor import ( "fmt" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/urfave/cli/v2" @@ -15,7 +17,7 @@ import ( // ---------------------------------------------------------------------------- // OpenSubstateDb opens a substate database as configured in the given parameters. -func OpenSubstateDb(cfg *utils.Config, ctxt *cli.Context) (res Provider[*substate.Substate], err error) { +func OpenSubstateDb(cfg *utils.Config, ctxt *cli.Context) (res Provider[txcontext.TxContext], err error) { // Substate is panicking if we are opening a non-existing directory. To mitigate // the damage, we recover here and forward an error instead. defer func() { @@ -36,7 +38,7 @@ type substateProvider struct { numParallelDecoders int } -func (s substateProvider) Run(from int, to int, consumer Consumer[*substate.Substate]) error { +func (s substateProvider) Run(from int, to int, consumer Consumer[txcontext.TxContext]) error { iter := substate.NewSubstateIterator(uint64(from), s.numParallelDecoders) defer iter.Release() for iter.Next() { @@ -44,7 +46,7 @@ func (s substateProvider) Run(from int, to int, consumer Consumer[*substate.Subs if tx.Block >= uint64(to) { return nil } - if err := consumer(TransactionInfo[*substate.Substate]{int(tx.Block), tx.Transaction, tx.Substate}); err != nil { + if err := consumer(TransactionInfo[txcontext.TxContext]{int(tx.Block), tx.Transaction, substatecontext.NewTxContext(tx.Substate)}); err != nil { return err } } diff --git a/executor/substate_provider_test.go b/executor/substate_provider_test.go index ecaaaa33d..6379bccdf 100644 --- a/executor/substate_provider_test.go +++ b/executor/substate_provider_test.go @@ -7,6 +7,7 @@ import ( "math/big" "testing" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "go.uber.org/mock/gomock" @@ -155,7 +156,7 @@ func TestSubstateProvider_IterationCanBeAbortedByConsumer(t *testing.T) { } } -func openSubstateDb(path string) (Provider[*substate.Substate], error) { +func openSubstateDb(path string) (Provider[txcontext.TxContext], error) { cfg := utils.Config{} cfg.AidaDb = path cfg.Workers = 1 diff --git a/executor/test_consumer.go b/executor/test_consumer.go index 83a269088..ecb71c29e 100644 --- a/executor/test_consumer.go +++ b/executor/test_consumer.go @@ -3,7 +3,7 @@ package executor import ( "github.com/Fantom-foundation/Aida/rpc" "github.com/Fantom-foundation/Aida/tracer/operation" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" ) //go:generate mockgen -source test_consumer.go -destination test_consumer_mocks.go -package executor @@ -14,11 +14,11 @@ import ( //---------------------------------------------------------------------------------// type TxConsumer interface { - Consume(block int, transaction int, substate *substate.Substate) error + Consume(block int, transaction int, substate txcontext.TxContext) error } -func toSubstateConsumer(c TxConsumer) Consumer[*substate.Substate] { - return func(info TransactionInfo[*substate.Substate]) error { +func toSubstateConsumer(c TxConsumer) Consumer[txcontext.TxContext] { + return func(info TransactionInfo[txcontext.TxContext]) error { return c.Consume(info.Block, info.Transaction, info.Data) } } diff --git a/executor/test_consumer_mocks.go b/executor/test_consumer_mocks.go index 84277d933..a2d773bf7 100644 --- a/executor/test_consumer_mocks.go +++ b/executor/test_consumer_mocks.go @@ -13,7 +13,7 @@ import ( rpc "github.com/Fantom-foundation/Aida/rpc" operation "github.com/Fantom-foundation/Aida/tracer/operation" - substate "github.com/Fantom-foundation/Substate" + txcontext "github.com/Fantom-foundation/Aida/txcontext" gomock "go.uber.org/mock/gomock" ) @@ -41,7 +41,7 @@ func (m *MockTxConsumer) EXPECT() *MockTxConsumerMockRecorder { } // Consume mocks base method. -func (m *MockTxConsumer) Consume(block, transaction int, substate *substate.Substate) error { +func (m *MockTxConsumer) Consume(block, transaction int, substate txcontext.TxContext) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Consume", block, transaction, substate) ret0, _ := ret[0].(error) diff --git a/go.mod b/go.mod index c935b53f9..6de2b1e7c 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/Fantom-foundation/Carmen/go v0.0.0-00010101000000-000000000000 - github.com/Fantom-foundation/Substate v0.0.0-20231129093658-a074f38004d0 + github.com/Fantom-foundation/Substate v0.0.0-20240117110940-3ffd9c344809 github.com/Fantom-foundation/Tosca v0.0.0-20230527064715-aa1fc97baebe github.com/Fantom-foundation/go-opera v1.1.1-rc.2 github.com/Fantom-foundation/lachesis-base v0.0.0-20221208123620-82a6d15f995c @@ -30,7 +30,7 @@ require ( github.com/urfave/cli/v2 v2.25.7 go.uber.org/mock v0.2.0 golang.org/x/exp v0.0.0-20231006140011-7918f672742d - golang.org/x/text v0.12.0 + golang.org/x/text v0.14.0 gonum.org/v1/gonum v0.12.0 ) @@ -115,11 +115,11 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect go.uber.org/atomic v1.10.0 // indirect - golang.org/x/crypto v0.12.0 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/image v0.11.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/sys v0.15.0 // indirect golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect diff --git a/go.sum b/go.sum index 932cfea51..f1a5872cd 100644 --- a/go.sum +++ b/go.sum @@ -51,7 +51,6 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= @@ -61,8 +60,8 @@ github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Fantom-foundation/Substate v0.0.0-20230224090651-4c8c024214f4/go.mod h1:/yIHWCDDJcdKMJYvOLdYOnHt5eUBF9XWnrvrNE+90ik= -github.com/Fantom-foundation/Substate v0.0.0-20231129093658-a074f38004d0 h1:7nh3f9T+dtIcH5uvc95Bi9n7IMra8U/fv41T3C3q5lA= -github.com/Fantom-foundation/Substate v0.0.0-20231129093658-a074f38004d0/go.mod h1:KoObQO1Wmf3ACjxcXDREHf+mtDF4MAXfHwtxMIdyhx8= +github.com/Fantom-foundation/Substate v0.0.0-20240117110940-3ffd9c344809 h1:3ufCktc5ngN2dbmAhgd0cgoyuZqOuW/BGh2z8fTVB4g= +github.com/Fantom-foundation/Substate v0.0.0-20240117110940-3ffd9c344809/go.mod h1:HjYEJRhJV7l6j+i2LI5mxtpYf55TSfE2SI26T2J3P90= github.com/Fantom-foundation/go-ethereum-substate v1.1.1-0.20230621093123-9c5132fd78c1 h1:yUK9WxGvVWGOQmFXu5RGIkrpiO7+42sM+obmkCsyL+g= github.com/Fantom-foundation/go-ethereum-substate v1.1.1-0.20230621093123-9c5132fd78c1/go.mod h1:Hu8U9SrXP6ABqtSNfJHw8lRGnr6tyma9PNZvwTweDjQ= github.com/Fantom-foundation/go-opera-substate v1.0.1-0.20230523093256-e592c59c5996 h1:YzgxEAK3dCLNvmY1pgLEgPuPOsGHFMxT6QLpZnXuxM8= @@ -728,7 +727,6 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= -github.com/urfave/cli/v2 v2.24.4/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= @@ -795,8 +793,8 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -982,8 +980,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -998,8 +996,9 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/profile/blockprofile/context.go b/profile/blockprofile/context.go index 64a92d3cf..5aa9865e6 100644 --- a/profile/blockprofile/context.go +++ b/profile/blockprofile/context.go @@ -6,7 +6,7 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/profile/graphutil" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/ethereum/go-ethereum/common" ) @@ -94,20 +94,22 @@ func interfere(u, v AddressSet) bool { } // findTxAddresses gets wallet/contract addresses of a transaction. -func findTxAddresses(tx executor.State[*substate.Substate]) AddressSet { +func findTxAddresses(tx executor.State[txcontext.TxContext]) AddressSet { addresses := AddressSet{} - for addr := range tx.Data.InputAlloc { + tx.Data.GetInputState().ForEachAccount(func(addr common.Address, acc txcontext.Account) { addresses[addr] = struct{}{} - } - for addr := range tx.Data.OutputAlloc { + }) + tx.Data.GetOutputState().ForEachAccount(func(addr common.Address, acc txcontext.Account) { addresses[addr] = struct{}{} - } + }) var zero common.Address - if tx.Data.Message.From != zero { - addresses[tx.Data.Message.From] = struct{}{} + from := tx.Data.GetMessage().From() + if from != zero { + addresses[from] = struct{}{} } - if tx.Data.Message.To != nil { - addresses[*tx.Data.Message.To] = struct{}{} + to := tx.Data.GetMessage().To() + if to != nil { + addresses[*to] = struct{}{} } return addresses } @@ -145,7 +147,7 @@ func (ctx *Context) dependencies(addresses AddressSet) graphutil.OrdinalSet { } // RecordTransaction collects addresses and computes earliest time. -func (ctx *Context) RecordTransaction(state executor.State[*substate.Substate], tTransaction time.Duration) error { +func (ctx *Context) RecordTransaction(state executor.State[txcontext.TxContext], tTransaction time.Duration) error { overheadTimer := time.Now() // update time for block and transaction @@ -154,7 +156,7 @@ func (ctx *Context) RecordTransaction(state executor.State[*substate.Substate], ctx.tTypes = append(ctx.tTypes, getTransactionType(state)) // update gas used for block and transaction - gasUsed := state.Data.Result.GasUsed + gasUsed := state.Data.GetReceipt().GetGasUsed() ctx.gasBlock += gasUsed ctx.gasTransactions = append(ctx.gasTransactions, gasUsed) @@ -258,18 +260,18 @@ func (ctx *Context) GetProfileData(curBlock uint64, tBlock time.Duration) (*Prof } // getTransactionType reads a message and determines a transaction type. -func getTransactionType(tx executor.State[*substate.Substate]) TxType { - msg := tx.Data.Message - to := msg.To - from := msg.From - alloc := tx.Data.InputAlloc +func getTransactionType(tx executor.State[txcontext.TxContext]) TxType { + msg := tx.Data.GetMessage() + to := msg.To() + from := msg.From() + alloc := tx.Data.GetInputState() zero := common.HexToAddress("0x0000000000000000000000000000000000000000") if to != nil { - account, exist := alloc[*to] + acc := alloc.Get(*to) // regular transaction - if !exist || len(account.Code) == 0 { + if acc == nil || len(acc.GetCode()) == 0 { return TransferTx // CALL transaction with contract bytecode } else { diff --git a/profile/blockprofile/context_test.go b/profile/blockprofile/context_test.go index ced34dbfc..e42b10aff 100644 --- a/profile/blockprofile/context_test.go +++ b/profile/blockprofile/context_test.go @@ -9,6 +9,8 @@ import ( "github.com/Fantom-foundation/Aida/executor" "github.com/Fantom-foundation/Aida/profile/graphutil" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/ethereum/go-ethereum/common" substate "github.com/Fantom-foundation/Substate" @@ -208,14 +210,13 @@ func TestDependenciesSimple3(t *testing.T) { // TestFindTxAddresses tests finding contract/wallet addresses of a transaction func TestFindTxAddresses(t *testing.T) { - // test substate.Transaction with empty fields - testTransaction := executor.State[*substate.Substate]{ - Data: &substate.Substate{ + testTransaction := executor.State[txcontext.TxContext]{ + Data: substatecontext.NewTxContext(&substate.Substate{ InputAlloc: substate.SubstateAlloc{}, OutputAlloc: substate.SubstateAlloc{}, Message: &substate.SubstateMessage{}, - }, + }), } addresses := findTxAddresses(testTransaction) @@ -228,34 +229,34 @@ func TestFindTxAddresses(t *testing.T) { addr2 := common.HexToAddress("0xFC00FACE00000000000000000000000000000002") addr3 := common.HexToAddress("0xFC00FACE00000000000000000000000000000003") addrs := []common.Address{addr1, addr2, addr3} - testTransaction = executor.State[*substate.Substate]{ - Data: &substate.Substate{ + testTransaction = executor.State[txcontext.TxContext]{ + Data: substatecontext.NewTxContext(&substate.Substate{ InputAlloc: substate.SubstateAlloc{addr1: &substate.SubstateAccount{}}, OutputAlloc: substate.SubstateAlloc{addr2: &substate.SubstateAccount{}, addr3: &substate.SubstateAccount{}}, Message: &substate.SubstateMessage{}, - }, + }), } addresses = findTxAddresses(testTransaction) if len(addresses) != 3 { t.Errorf("Unexpected result") } for _, addr := range addrs { - if _, ok := addresses[addr]; !ok { + if _, ok := addresses[common.Address(addr)]; !ok { t.Errorf("Unexpected result") } } - // test if substate.Message.To == nil and substate.Message.From == zero + // test if substate.SubstateMessage.To == nil and substate.SubstateMessage.From == zero var zero common.Address - testTransaction = executor.State[*substate.Substate]{ - Data: &substate.Substate{ + testTransaction = executor.State[txcontext.TxContext]{ + Data: substatecontext.NewTxContext(&substate.Substate{ InputAlloc: substate.SubstateAlloc{addr1: &substate.SubstateAccount{}}, OutputAlloc: substate.SubstateAlloc{addr2: &substate.SubstateAccount{}, addr1: &substate.SubstateAccount{}}, Message: &substate.SubstateMessage{ - From: zero, + From: common.Address(zero), To: nil, }, - }, + }), } addresses = findTxAddresses(testTransaction) @@ -276,8 +277,8 @@ func TestRecordTransaction(t *testing.T) { addr1 := common.HexToAddress("0xFC00FACE00000000000000000000000000000001") addr2 := common.HexToAddress("0xFC00FACE00000000000000000000000000000002") addr3 := common.HexToAddress("0xFC00FACE00000000000000000000000000000003") - tx := executor.State[*substate.Substate]{ - Data: &substate.Substate{ + tx := executor.State[txcontext.TxContext]{ + Data: substatecontext.NewTxContext(&substate.Substate{ InputAlloc: substate.SubstateAlloc{addr1: &substate.SubstateAccount{}}, OutputAlloc: substate.SubstateAlloc{addr2: &substate.SubstateAccount{}, addr3: &substate.SubstateAccount{}}, Message: &substate.SubstateMessage{ @@ -287,7 +288,7 @@ func TestRecordTransaction(t *testing.T) { Result: &substate.SubstateResult{ GasUsed: 11111, }, - }, + }), Transaction: 1, Block: 0, } @@ -345,8 +346,8 @@ func TestRecordTransaction(t *testing.T) { } // construct second transaction - tx2 := executor.State[*substate.Substate]{ - Data: &substate.Substate{ + tx2 := executor.State[txcontext.TxContext]{ + Data: substatecontext.NewTxContext(&substate.Substate{ InputAlloc: substate.SubstateAlloc{addr1: &substate.SubstateAccount{}}, OutputAlloc: substate.SubstateAlloc{addr2: &substate.SubstateAccount{}, addr3: &substate.SubstateAccount{}}, Message: &substate.SubstateMessage{ @@ -356,7 +357,7 @@ func TestRecordTransaction(t *testing.T) { Result: &substate.SubstateResult{ GasUsed: 22222, }, - }, + }), Transaction: 2, Block: 0, } @@ -480,12 +481,14 @@ func TestGetTransactionType(t *testing.T) { toAddr := common.HexToAddress("0xabcdef0000000000000000000000000000000001") fromAddr1 := common.HexToAddress("0xabcdef0000000000000000000000000000000002") fromAddr2 := common.HexToAddress("0x0000000000000000000000000000000000000000") + sub := &substate.Substate{ + InputAlloc: substate.SubstateAlloc{}, + Message: &substate.SubstateMessage{}, + } + data := substatecontext.NewTxContext(sub) - testTransaction := executor.State[*substate.Substate]{ - Data: &substate.Substate{ - InputAlloc: substate.SubstateAlloc{}, - Message: &substate.SubstateMessage{}, - }, + testTransaction := executor.State[txcontext.TxContext]{ + Data: data, Transaction: 0, } @@ -495,29 +498,33 @@ func TestGetTransactionType(t *testing.T) { } // expect transafer type - testTransaction.Data.Message.To = &toAddr + sub.Message.To = &toAddr + testTransaction.Data = substatecontext.NewTxContext(sub) // to address doesn't exist in input substate if tt := getTransactionType(testTransaction); tt != TransferTx { t.Errorf("incorrect transaction type, got: %v, expected %v", TypeLabel[tt], TypeLabel[TransferTx]) } // to address exists in input substate but doesn't have byte-code - testTransaction.Data.InputAlloc[toAddr] = substate.NewSubstateAccount(1, big.NewInt(1), []byte{}) + sub.InputAlloc[toAddr] = substate.NewSubstateAccount(1, big.NewInt(1), []byte{}) + testTransaction.Data = substatecontext.NewTxContext(sub) if tt := getTransactionType(testTransaction); tt != TransferTx { t.Errorf("incorrect transaction type, got: %v, expected %v", TypeLabel[tt], TypeLabel[TransferTx]) } // expect call type // to address exists in input substate and has byte-code - testTransaction.Data.InputAlloc[toAddr].Code = []byte{1, 2, 3, 4} - testTransaction.Data.Message.From = fromAddr1 + sub.InputAlloc[toAddr].Code = []byte{1, 2, 3, 4} + sub.Message.From = fromAddr1 + testTransaction.Data = substatecontext.NewTxContext(sub) if tt := getTransactionType(testTransaction); tt != CallTx { t.Errorf("incorrect transaction type, got: %v, expected %v", TypeLabel[tt], TypeLabel[CallTx]) } // expect epoch sealing type // from address 0 to an sfc address (with byte-code - testTransaction.Data.Message.From = fromAddr2 - testTransaction.Data.InputAlloc[toAddr] = substate.NewSubstateAccount(1, big.NewInt(1), []byte{1, 2, 3, 4}) + sub.Message.From = fromAddr2 + sub.InputAlloc[toAddr] = substate.NewSubstateAccount(1, big.NewInt(1), []byte{1, 2, 3, 4}) + testTransaction.Data = substatecontext.NewTxContext(sub) if tt := getTransactionType(testTransaction); tt != MaintenanceTx { t.Errorf("incorrect transaction type, got: %v, expected %v", TypeLabel[tt], TypeLabel[MaintenanceTx]) } diff --git a/state/carmen.go b/state/carmen.go index 478923152..f47fa5971 100644 --- a/state/carmen.go +++ b/state/carmen.go @@ -5,10 +5,10 @@ import ( "math/big" "strings" + "github.com/Fantom-foundation/Aida/txcontext" cc "github.com/Fantom-foundation/Carmen/go/common" carmen "github.com/Fantom-foundation/Carmen/go/state" _ "github.com/Fantom-foundation/Carmen/go/state/cppstate" - substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -277,13 +277,13 @@ func (s *carmenVmStateDB) Prepare(thash common.Hash, ti int) { // ignored } -func (s *carmenStateDB) PrepareSubstate(substate *substate.SubstateAlloc, block uint64) { +func (s *carmenStateDB) PrepareSubstate(substate txcontext.WorldState, block uint64) { // ignored } -func (s *carmenVmStateDB) GetSubstatePostAlloc() substate.SubstateAlloc { +func (s *carmenVmStateDB) GetSubstatePostAlloc() txcontext.WorldState { // ignored - return substate.SubstateAlloc{} + return nil } func (s *carmenVmStateDB) AddPreimage(common.Hash, []byte) { diff --git a/state/geth.go b/state/geth.go index 2e2fc5aef..492f0085e 100644 --- a/state/geth.go +++ b/state/geth.go @@ -4,7 +4,8 @@ import ( "fmt" "math/big" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/core/rawdb" @@ -219,15 +220,16 @@ func (s *gethStateDB) Prepare(thash common.Hash, ti int) { } } -func (s *gethStateDB) PrepareSubstate(substate *substate.SubstateAlloc, block uint64) { +func (s *gethStateDB) PrepareSubstate(substate txcontext.WorldState, block uint64) { // ignored } -func (s *gethStateDB) GetSubstatePostAlloc() substate.SubstateAlloc { +func (s *gethStateDB) GetSubstatePostAlloc() txcontext.WorldState { if db, ok := s.db.(*geth.StateDB); ok { - return db.GetSubstatePostAlloc() + return substatecontext.NewWorldState(db.GetSubstatePostAlloc()) } - return substate.SubstateAlloc{} + + return nil } func (s *gethStateDB) Close() error { diff --git a/state/memory.go b/state/memory.go index 7f8c9bc8b..91ae5f43b 100644 --- a/state/memory.go +++ b/state/memory.go @@ -4,6 +4,8 @@ import ( "fmt" "math/big" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -13,19 +15,19 @@ func MakeEmptyGethInMemoryStateDB(variant string) (StateDB, error) { if variant != "" { return nil, fmt.Errorf("unknown variant: %v", variant) } - return MakeInMemoryStateDB(&substate.SubstateAlloc{}, 0), nil + return MakeInMemoryStateDB(substatecontext.NewWorldState(make(substate.SubstateAlloc)), 0), nil } // MakeInMemoryStateDB creates a StateDB instance reflecting the state // captured by the provided Substate allocation. -func MakeInMemoryStateDB(alloc *substate.SubstateAlloc, block uint64) StateDB { - return &inMemoryStateDB{alloc: alloc, state: makeSnapshot(nil, 0), blockNum: block} +func MakeInMemoryStateDB(ws txcontext.WorldState, block uint64) StateDB { + return &inMemoryStateDB{ws: ws, state: makeSnapshot(nil, 0), blockNum: block} } // inMemoryStateDB implements the interface of a state.StateDB and can be // used as a fast, in-memory replacement of the state DB. type inMemoryStateDB struct { - alloc *substate.SubstateAlloc + ws txcontext.WorldState state *snapshot snapshot_counter int blockNum uint64 @@ -103,11 +105,11 @@ func (db *inMemoryStateDB) GetBalance(addr common.Address) *big.Int { return new(big.Int).Set(val) } } - account, exists := (*db.alloc)[addr] - if !exists { + acc := db.ws.Get(addr) + if acc == nil { return new(big.Int).Set(common.Big0) } - return new(big.Int).Set(account.Balance) + return new(big.Int).Set(acc.GetBalance()) } func (db *inMemoryStateDB) GetNonce(addr common.Address) uint64 { @@ -117,11 +119,11 @@ func (db *inMemoryStateDB) GetNonce(addr common.Address) uint64 { return val } } - account, exists := (*db.alloc)[addr] - if !exists { + acc := db.ws.Get(addr) + if acc == nil { return 0 } - return account.Nonce + return acc.GetNonce() } func (db *inMemoryStateDB) SetNonce(addr common.Address, value uint64) { @@ -143,11 +145,10 @@ func (db *inMemoryStateDB) GetCode(addr common.Address) []byte { return val } } - account, exists := (*db.alloc)[addr] - if !exists { + if !db.ws.Has(addr) { return []byte{} } - return account.Code + return db.ws.Get(addr).GetCode() } func (db *inMemoryStateDB) SetCode(addr common.Address, code []byte) { @@ -170,11 +171,10 @@ func (db *inMemoryStateDB) GetRefund() uint64 { } func (db *inMemoryStateDB) GetCommittedState(addr common.Address, key common.Hash) common.Hash { - account, exists := (*db.alloc)[addr] - if !exists { + if !db.ws.Has(addr) { return common.Hash{} } - return account.Storage[key] + return db.ws.Get(addr).GetStorageAt(key) } func (db *inMemoryStateDB) GetState(addr common.Address, key common.Hash) common.Hash { @@ -186,12 +186,13 @@ func (db *inMemoryStateDB) GetState(addr common.Address, key common.Hash) common return val } } - account, exists := (*db.alloc)[addr] - if !exists { + + if !db.ws.Has(addr) { db.state.storage[slot] = common.Hash{} return common.Hash{} } - return account.Storage[key] + + return db.ws.Get(addr).GetStorageAt(key) } func (db *inMemoryStateDB) SetState(addr common.Address, key common.Hash, value common.Hash) { @@ -221,8 +222,7 @@ func (db *inMemoryStateDB) Exist(addr common.Address) bool { return true } } - _, exists := (*db.alloc)[addr] - return exists + return db.ws.Has(addr) } func (db *inMemoryStateDB) Empty(addr common.Address) bool { @@ -346,7 +346,8 @@ func (s *inMemoryStateDB) Error() error { return nil } -func (db *inMemoryStateDB) GetEffects() substate.SubstateAlloc { +func (db *inMemoryStateDB) getEffects() substate.SubstateAlloc { + // todo this should return txcontext.WorldState // collect all modified accounts touched := map[common.Address]int{} for state := db.state; state != nil; state = state.parent { @@ -356,13 +357,13 @@ func (db *inMemoryStateDB) GetEffects() substate.SubstateAlloc { } // build state of all touched addresses - res := substate.SubstateAlloc{} + res := make(substate.SubstateAlloc) for addr := range touched { - cur := &substate.SubstateAccount{} + cur := new(substate.SubstateAccount) cur.Nonce = db.GetNonce(addr) cur.Balance = db.GetBalance(addr) cur.Code = db.GetCode(addr) - cur.Storage = map[common.Hash]common.Hash{} + cur.Storage = make(map[common.Hash]common.Hash) reported := map[common.Hash]int{} for state := db.state; state != nil; state = state.parent { @@ -383,12 +384,25 @@ func (db *inMemoryStateDB) GetEffects() substate.SubstateAlloc { return res } -func (db *inMemoryStateDB) GetSubstatePostAlloc() substate.SubstateAlloc { - // Use the pre-alloc ... - res := *db.alloc +func (db *inMemoryStateDB) GetSubstatePostAlloc() txcontext.WorldState { + // todo we should not copy the map + // rn the inMemoryDb is broken and unused anyway, when fixed this should be reworked + res := make(substate.SubstateAlloc) + db.ws.ForEachAccount(func(addr common.Address, acc txcontext.Account) { + storage := make(map[common.Hash]common.Hash) + acc.ForEachStorage(func(keyHash common.Hash, valueHash common.Hash) { + storage[keyHash] = valueHash + }) + res[addr] = &substate.SubstateAccount{ + Nonce: acc.GetNonce(), + Balance: acc.GetBalance(), + Storage: storage, + Code: acc.GetCode(), + } + }) // ... and extend with effects - for key, value := range db.GetEffects() { + for key, value := range db.getEffects() { entry, exists := res[key] if !exists { res[key] = value @@ -419,7 +433,7 @@ func (db *inMemoryStateDB) GetSubstatePostAlloc() substate.SubstateAlloc { } } - return res + return substatecontext.NewWorldState(res) } func (db *inMemoryStateDB) BeginTransaction(number uint32) { @@ -468,8 +482,8 @@ func (s *inMemoryStateDB) GetArchiveBlockHeight() (uint64, bool, error) { return 0, false, fmt.Errorf("archive states are not (yet) supported by this DB implementation") } -func (db *inMemoryStateDB) PrepareSubstate(alloc *substate.SubstateAlloc, block uint64) { - db.alloc = alloc +func (db *inMemoryStateDB) PrepareSubstate(alloc txcontext.WorldState, block uint64) { + db.ws = alloc db.state = makeSnapshot(nil, 0) db.blockNum = block } diff --git a/state/opera.go b/state/opera.go index 66c1c41ed..b6a4d5535 100644 --- a/state/opera.go +++ b/state/opera.go @@ -7,7 +7,8 @@ import ( "path" "github.com/Fantom-foundation/Aida/logger" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/go-opera/cmd/opera/launcher" "github.com/Fantom-foundation/go-opera/gossip" "github.com/Fantom-foundation/go-opera/integration" @@ -296,11 +297,11 @@ func (s *operaStateDB) ForEachStorage(addr common.Address, cb func(common.Hash, return s.db.ForEachStorage(addr, cb) } -func (s *operaStateDB) GetSubstatePostAlloc() substate.SubstateAlloc { - return s.db.GetSubstatePostAlloc() +func (s *operaStateDB) GetSubstatePostAlloc() txcontext.WorldState { + return substatecontext.NewWorldState(s.db.GetSubstatePostAlloc()) } -func (s *operaStateDB) PrepareSubstate(substate *substate.SubstateAlloc, block uint64) { +func (s *operaStateDB) PrepareSubstate(substate txcontext.WorldState, block uint64) { // ignored } diff --git a/state/proxy/deletion.go b/state/proxy/deletion.go index 9fa5096db..192304be8 100644 --- a/state/proxy/deletion.go +++ b/state/proxy/deletion.go @@ -5,7 +5,7 @@ import ( "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -248,11 +248,11 @@ func (r *DeletionProxy) Error() error { } // GetSubstatePostAlloc gets substate post allocation. -func (r *DeletionProxy) GetSubstatePostAlloc() substate.SubstateAlloc { +func (r *DeletionProxy) GetSubstatePostAlloc() txcontext.WorldState { return r.db.GetSubstatePostAlloc() } -func (r *DeletionProxy) PrepareSubstate(substate *substate.SubstateAlloc, block uint64) { +func (r *DeletionProxy) PrepareSubstate(substate txcontext.WorldState, block uint64) { r.db.PrepareSubstate(substate, block) } diff --git a/state/proxy/logger.go b/state/proxy/logger.go index f802a695c..b53ab98dc 100644 --- a/state/proxy/logger.go +++ b/state/proxy/logger.go @@ -7,7 +7,7 @@ import ( "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -280,14 +280,14 @@ func (s *loggingVmStateDb) Prepare(thash common.Hash, ti int) { s.writeLog("Prepare, %v, %v", thash, ti) } -func (s *LoggingStateDb) PrepareSubstate(substate *substate.SubstateAlloc, block uint64) { +func (s *LoggingStateDb) PrepareSubstate(substate txcontext.WorldState, block uint64) { s.state.PrepareSubstate(substate, block) - s.writeLog("PrepareSubstate, %v", PrettySubstateAlloc(*substate)) + s.writeLog("PrepareSubstate, %v", substate.String()) } -func (s *loggingVmStateDb) GetSubstatePostAlloc() substate.SubstateAlloc { +func (s *loggingVmStateDb) GetSubstatePostAlloc() txcontext.WorldState { res := s.db.GetSubstatePostAlloc() - s.writeLog("GetSubstatePostAlloc, %v", PrettySubstateAlloc(res)) + s.writeLog("GetSubstatePostAlloc, %v", res.String()) return res } diff --git a/state/proxy/profiler.go b/state/proxy/profiler.go index baa02bf44..7a0244c77 100644 --- a/state/proxy/profiler.go +++ b/state/proxy/profiler.go @@ -8,8 +8,8 @@ import ( "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" "github.com/Fantom-foundation/Aida/tracer/operation" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/Fantom-foundation/Aida/utils/analytics" - substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -381,11 +381,11 @@ func (p *ProfilerProxy) Commit(deleteEmptyObjects bool) (common.Hash, error) { } // GetSubstatePostAlloc gets substate post allocation. -func (p *ProfilerProxy) GetSubstatePostAlloc() substate.SubstateAlloc { +func (p *ProfilerProxy) GetSubstatePostAlloc() txcontext.WorldState { return p.db.GetSubstatePostAlloc() } -func (p *ProfilerProxy) PrepareSubstate(substate *substate.SubstateAlloc, block uint64) { +func (p *ProfilerProxy) PrepareSubstate(substate txcontext.WorldState, block uint64) { p.db.PrepareSubstate(substate, block) } diff --git a/state/proxy/recorder.go b/state/proxy/recorder.go index 1b5e69ea9..61967e786 100644 --- a/state/proxy/recorder.go +++ b/state/proxy/recorder.go @@ -7,7 +7,7 @@ import ( "github.com/Fantom-foundation/Aida/state" "github.com/Fantom-foundation/Aida/tracer/context" "github.com/Fantom-foundation/Aida/tracer/operation" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -306,11 +306,11 @@ func (r *RecorderProxy) Error() error { } // GetSubstatePostAlloc gets substate post allocation. -func (r *RecorderProxy) GetSubstatePostAlloc() substate.SubstateAlloc { +func (r *RecorderProxy) GetSubstatePostAlloc() txcontext.WorldState { return r.db.GetSubstatePostAlloc() } -func (r *RecorderProxy) PrepareSubstate(substate *substate.SubstateAlloc, block uint64) { +func (r *RecorderProxy) PrepareSubstate(substate txcontext.WorldState, block uint64) { r.db.PrepareSubstate(substate, block) } diff --git a/state/proxy/shadow.go b/state/proxy/shadow.go index 2e1a4d2a7..affd9f275 100644 --- a/state/proxy/shadow.go +++ b/state/proxy/shadow.go @@ -10,7 +10,7 @@ import ( "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -270,11 +270,11 @@ func (s *shadowVmStateDb) Prepare(thash common.Hash, ti int) { s.run("Prepare", func(s state.VmStateDB) { s.Prepare(thash, ti) }) } -func (s *shadowStateDb) PrepareSubstate(substate *substate.SubstateAlloc, block uint64) { +func (s *shadowStateDb) PrepareSubstate(substate txcontext.WorldState, block uint64) { s.run("PrepareSubstate", func(s state.StateDB) { s.PrepareSubstate(substate, block) }) } -func (s *shadowVmStateDb) GetSubstatePostAlloc() substate.SubstateAlloc { +func (s *shadowVmStateDb) GetSubstatePostAlloc() txcontext.WorldState { // Skip comparing those results. s.shadow.GetSubstatePostAlloc() return s.prime.GetSubstatePostAlloc() diff --git a/state/proxy/substate.go b/state/proxy/substate.go deleted file mode 100644 index 5b35e6229..000000000 --- a/state/proxy/substate.go +++ /dev/null @@ -1,52 +0,0 @@ -package proxy - -import ( - "fmt" - "sort" - "strings" - - substate "github.com/Fantom-foundation/Substate" - "github.com/ethereum/go-ethereum/common" -) - -// PrettySubstateAlloc is a wrapper over a SubstateAlloc that adds human -// readable, stable --and thus diff-able -- pretty printing to it. -type PrettySubstateAlloc substate.SubstateAlloc - -func (a PrettySubstateAlloc) String() string { - builder := strings.Builder{} - builder.WriteString(fmt.Sprintf("SubstateAlloc{\n\tsize: %d\n", len(a))) - keys := []common.Address{} - for key := range a { - keys = append(keys, key) - } - sort.Slice(keys, func(i, j int) bool { return keys[i].String() < keys[j].String() }) - - builder.WriteString("\tAccounts:\n") - for _, key := range keys { - builder.WriteString(fmt.Sprintf("\t\t%x: %v\n", key, prettySubstateAccount{a[key]})) - } - builder.WriteString("}") - return builder.String() -} - -type prettySubstateAccount struct { - *substate.SubstateAccount -} - -func (a prettySubstateAccount) String() string { - builder := strings.Builder{} - builder.WriteString(fmt.Sprintf("Account{\n\t\t\tnonce: %d\n\t\t\tbalance %v\n", a.Nonce, a.Balance)) - - builder.WriteString("\t\t\tStorage{\n") - keys := []common.Hash{} - for key := range a.Storage { - keys = append(keys, key) - } - sort.Slice(keys, func(i, j int) bool { return keys[i].String() < keys[j].String() }) - for _, key := range keys { - builder.WriteString(fmt.Sprintf("\t\t\t\t%v=%v\n", key, a.Storage[key])) - } - builder.WriteString("\t\t\t}\n\t\t}") - return builder.String() -} diff --git a/state/state.go b/state/state.go index 398ded80b..d1286cc48 100644 --- a/state/state.go +++ b/state/state.go @@ -6,7 +6,7 @@ import ( "fmt" "math/big" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -84,7 +84,7 @@ type VmStateDB interface { // ---- Optional Development & Debugging Features ---- // Substate specific - GetSubstatePostAlloc() substate.SubstateAlloc + GetSubstatePostAlloc() txcontext.WorldState } // NonCommittableStateDB is an extension of the VmStateDB interface and is intended @@ -166,7 +166,7 @@ type StateDB interface { // Used to initiate the state DB for the next transaction. // This is mainly for development purposes to support in-memory DB implementations. - PrepareSubstate(substate *substate.SubstateAlloc, block uint64) + PrepareSubstate(substate txcontext.WorldState, block uint64) // Used to retrieve the shadow DB (if there is one) for testing purposes so that // the shadow DB can be used to query state directly. If there is no shadow DB, diff --git a/state/state_mocks.go b/state/state_mocks.go index 9554ddb4d..298dde870 100644 --- a/state/state_mocks.go +++ b/state/state_mocks.go @@ -12,7 +12,7 @@ import ( big "math/big" reflect "reflect" - substate "github.com/Fantom-foundation/Substate" + txcontext "github.com/Fantom-foundation/Aida/txcontext" common "github.com/ethereum/go-ethereum/common" types "github.com/ethereum/go-ethereum/core/types" gomock "go.uber.org/mock/gomock" @@ -332,10 +332,10 @@ func (mr *MockVmStateDBMockRecorder) GetState(arg0, arg1 any) *gomock.Call { } // GetSubstatePostAlloc mocks base method. -func (m *MockVmStateDB) GetSubstatePostAlloc() substate.SubstateAlloc { +func (m *MockVmStateDB) GetSubstatePostAlloc() txcontext.WorldState { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSubstatePostAlloc") - ret0, _ := ret[0].(substate.SubstateAlloc) + ret0, _ := ret[0].(txcontext.WorldState) return ret0 } @@ -826,10 +826,10 @@ func (mr *MockNonCommittableStateDBMockRecorder) GetState(arg0, arg1 any) *gomoc } // GetSubstatePostAlloc mocks base method. -func (m *MockNonCommittableStateDB) GetSubstatePostAlloc() substate.SubstateAlloc { +func (m *MockNonCommittableStateDB) GetSubstatePostAlloc() txcontext.WorldState { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSubstatePostAlloc") - ret0, _ := ret[0].(substate.SubstateAlloc) + ret0, _ := ret[0].(txcontext.WorldState) return ret0 } @@ -1494,10 +1494,10 @@ func (mr *MockStateDBMockRecorder) GetState(arg0, arg1 any) *gomock.Call { } // GetSubstatePostAlloc mocks base method. -func (m *MockStateDB) GetSubstatePostAlloc() substate.SubstateAlloc { +func (m *MockStateDB) GetSubstatePostAlloc() txcontext.WorldState { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSubstatePostAlloc") - ret0, _ := ret[0].(substate.SubstateAlloc) + ret0, _ := ret[0].(txcontext.WorldState) return ret0 } @@ -1560,7 +1560,7 @@ func (mr *MockStateDBMockRecorder) PrepareAccessList(sender, dest, precompiles, } // PrepareSubstate mocks base method. -func (m *MockStateDB) PrepareSubstate(substate *substate.SubstateAlloc, block uint64) { +func (m *MockStateDB) PrepareSubstate(substate txcontext.WorldState, block uint64) { m.ctrl.T.Helper() m.ctrl.Call(m, "PrepareSubstate", substate, block) } diff --git a/state/substate.go b/state/substate.go index 518f467d8..7da267908 100644 --- a/state/substate.go +++ b/state/substate.go @@ -7,7 +7,7 @@ import ( "math/big" "sync" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" @@ -123,18 +123,20 @@ func getHash(addr common.Address, code []byte) common.Hash { return res } -// MakeOffTheChainStateDB returns an in-memory *state.StateDB initialized with alloc -func MakeOffTheChainStateDB(alloc substate.SubstateAlloc, block uint64, chainConduit *ChainConduit) (StateDB, error) { +// MakeOffTheChainStateDB returns an in-memory *state.StateDB initialized with ws +func MakeOffTheChainStateDB(alloc txcontext.WorldState, block uint64, chainConduit *ChainConduit) (StateDB, error) { statedb := NewOffTheChainStateDB() - for addr, a := range alloc { - statedb.SetPrehashedCode(addr, getHash(addr, a.Code), a.Code) - statedb.SetNonce(addr, a.Nonce) - statedb.SetBalance(addr, a.Balance) + alloc.ForEachAccount(func(addr common.Address, acc txcontext.Account) { + code := acc.GetCode() + statedb.SetPrehashedCode(addr, getHash(addr, code), code) + statedb.SetNonce(addr, acc.GetNonce()) + statedb.SetBalance(addr, acc.GetBalance()) // DON'T USE SetStorage because it makes REVERT and dirtyStorage unavailble - for k, v := range a.Storage { - statedb.SetState(addr, k, v) - } - } + acc.ForEachStorage(func(keyHash common.Hash, valueHash common.Hash) { + statedb.SetState(addr, keyHash, valueHash) + }) + }) + // Commit and re-open to start with a clean state. _, err := statedb.Commit(false) if err != nil { diff --git a/stochastic/event_proxy.go b/stochastic/event_proxy.go index 1196322e1..26d5534ad 100644 --- a/stochastic/event_proxy.go +++ b/stochastic/event_proxy.go @@ -6,7 +6,7 @@ import ( "math/big" "github.com/Fantom-foundation/Aida/state" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -321,12 +321,12 @@ func (p *EventProxy) Error() error { } // GetSubstatePostAlloc gets substate post allocation. -func (p *EventProxy) GetSubstatePostAlloc() substate.SubstateAlloc { +func (p *EventProxy) GetSubstatePostAlloc() txcontext.WorldState { // call real StateDB return p.db.GetSubstatePostAlloc() } -func (p *EventProxy) PrepareSubstate(substate *substate.SubstateAlloc, block uint64) { +func (p *EventProxy) PrepareSubstate(substate txcontext.WorldState, block uint64) { p.db.PrepareSubstate(substate, block) } diff --git a/tracer/operation/operation_test.go b/tracer/operation/operation_test.go index f7d6ebdcd..89610f8e5 100644 --- a/tracer/operation/operation_test.go +++ b/tracer/operation/operation_test.go @@ -10,7 +10,7 @@ import ( "github.com/Fantom-foundation/Aida/state" "github.com/Fantom-foundation/Aida/tracer/context" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -244,13 +244,13 @@ func (s *MockStateDB) GetLogs(hash common.Hash, blockHash common.Hash) []*types. return nil } -func (s *MockStateDB) PrepareSubstate(substate *substate.SubstateAlloc, block uint64) { +func (s *MockStateDB) PrepareSubstate(substate txcontext.WorldState, block uint64) { // ignored } -func (s *MockStateDB) GetSubstatePostAlloc() substate.SubstateAlloc { +func (s *MockStateDB) GetSubstatePostAlloc() txcontext.WorldState { // ignored - return substate.SubstateAlloc{} + return nil } func (s *MockStateDB) Close() error { diff --git a/txcontext/account.go b/txcontext/account.go new file mode 100644 index 000000000..e6522f7c9 --- /dev/null +++ b/txcontext/account.go @@ -0,0 +1,95 @@ +package txcontext + +import ( + "bytes" + "fmt" + "math/big" + "sort" + "strings" + + "github.com/ethereum/go-ethereum/common" +) + +// Account represents an interface for interacting with an Ethereum-like account. +type Account interface { + // GetNonce returns the current nonce of the account. + GetNonce() uint64 + + // GetBalance returns the current balance of the account. + GetBalance() *big.Int + + HasStorageAt(key common.Hash) bool + + // GetStorageAt returns the value stored at the specified storage key of the account. + GetStorageAt(key common.Hash) common.Hash + + // GetCode returns the bytecode of the account. + GetCode() []byte + + // GetStorageSize returns the size of Accounts Storage. + GetStorageSize() int + + // ForEachStorage iterates over each account's storage in the collection + // and invokes the provided AccountHandler function for each account. + ForEachStorage(StorageHandler) + + // String returns human-readable version of alloc. + // Note: Have a look at AccountString + String() string +} + +type StorageHandler func(keyHash common.Hash, valueHash common.Hash) + +func AccountEqual(a, y Account) (isEqual bool) { + if a == y { + return true + } + + if (a == nil || y == nil) && a != y { + return false + } + + // check values + equal := a.GetNonce() == y.GetNonce() && + a.GetBalance().Cmp(y.GetBalance()) == 0 && + bytes.Equal(a.GetCode(), y.GetCode()) && + a.GetStorageSize() == y.GetStorageSize() + if !equal { + return false + } + + zeroHash := common.Hash{} + a.ForEachStorage(func(aKey common.Hash, aHash common.Hash) { + yHash := y.GetStorageAt(aKey) + if yHash == zeroHash { + isEqual = false + return + } + + if yHash != aHash { + isEqual = false + return + } + }) + + return true +} + +func AccountString(a Account) string { + builder := strings.Builder{} + builder.WriteString(fmt.Sprintf("Account{\n\t\t\tnonce: %d\n\t\t\tbalance %v\n", a.GetNonce(), a.GetBalance())) + + builder.WriteString("\t\t\tStorage{\n") + var keyHashes []common.Hash + + a.ForEachStorage(func(keyHash common.Hash, _ common.Hash) { + keyHashes = append(keyHashes, keyHash) + }) + + sort.Slice(keyHashes, func(i, j int) bool { return keyHashes[i].String() < keyHashes[j].String() }) + for _, key := range keyHashes { + builder.WriteString(fmt.Sprintf("\t\t\t\t%v=%v\n", key, a.GetStorageAt(key))) + } + builder.WriteString("\t\t\t}\n\t\t}") + return builder.String() +} diff --git a/txcontext/block_environment.go b/txcontext/block_environment.go new file mode 100644 index 000000000..3252fa861 --- /dev/null +++ b/txcontext/block_environment.go @@ -0,0 +1,31 @@ +package txcontext + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" +) + +// BlockEnvironment represents an interface for retrieving and modifying Ethereum-like blockchain environment information. +type BlockEnvironment interface { + // GetCoinbase returns the coinbase address. + GetCoinbase() common.Address + + // GetDifficulty returns the current difficulty level. + GetDifficulty() *big.Int + + // GetGasLimit returns the maximum amount of gas that can be used in a block. + GetGasLimit() uint64 + + // GetNumber returns the current block number. + GetNumber() uint64 + + // GetTimestamp returns the timestamp of the current block. + GetTimestamp() uint64 + + // GetBlockHash returns the hash of the block with the given number. + GetBlockHash(blockNumber uint64) common.Hash + + // GetBaseFee returns the base fee for transactions in the current block. + GetBaseFee() *big.Int +} diff --git a/txcontext/receipt.go b/txcontext/receipt.go new file mode 100644 index 000000000..becb16c05 --- /dev/null +++ b/txcontext/receipt.go @@ -0,0 +1,72 @@ +package txcontext + +import ( + "bytes" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Receipt represents an interface for managing and retrieving the result of a blockchain transaction or contract execution. +type Receipt interface { + // GetStatus returns the status code indicating the success or failure of the transaction or execution. + GetStatus() uint64 + + // GetBloom returns the Bloom filter associated with the transaction or execution result. + GetBloom() types.Bloom + + // GetLogs returns the logs generated during the transaction or contract execution. + GetLogs() []*types.Log + + // GetContractAddress returns the address of the contract created, if any. + GetContractAddress() common.Address + + // GetGasUsed returns the amount of gas used during the transaction or contract execution. + GetGasUsed() uint64 + + // Equal checks if the current result is equal to the provided result. + // Note: Have a look at ReceiptEqual. + Equal(y Receipt) bool +} + +func ReceiptEqual(x, y Receipt) bool { + if x == y { + return true + } + + if (x == nil || y == nil) && x != y { + return false + } + + rLogs := x.GetLogs() + yLogs := y.GetLogs() + + equal := x.GetStatus() == y.GetStatus() && + x.GetBloom() == y.GetBloom() && + (len(rLogs)) == len(yLogs) && + x.GetContractAddress() == y.GetContractAddress() && + x.GetGasUsed() == y.GetGasUsed() + if !equal { + return false + } + + for i, log := range rLogs { + yLog := yLogs[i] + + equal := log.Address == yLog.Address && + len(log.Topics) == len(yLog.Topics) && + bytes.Equal(log.Data, yLog.Data) + if !equal { + return false + } + + for i, xt := range log.Topics { + yt := yLog.Topics[i] + if xt != yt { + return false + } + } + } + + return true +} diff --git a/txcontext/substate/account.go b/txcontext/substate/account.go new file mode 100644 index 000000000..bcf963385 --- /dev/null +++ b/txcontext/substate/account.go @@ -0,0 +1,56 @@ +package substate + +import ( + "math/big" + + "github.com/Fantom-foundation/Aida/txcontext" + oldSubstate "github.com/Fantom-foundation/Substate" + "github.com/ethereum/go-ethereum/common" +) + +// Deprecated: This is a workaround before oldSubstate repository is migrated to new structure. +// Use NewSubstateAccount instead. +func NewAccount(acc *oldSubstate.SubstateAccount) txcontext.Account { + return &account{acc} +} + +// Deprecated: This is a workaround before oldSubstate repository is migrated to new structure. +// Use substateAccount instead. +type account struct { + *oldSubstate.SubstateAccount +} + +func (a *account) GetNonce() uint64 { + return a.Nonce +} + +func (a *account) GetBalance() *big.Int { + return a.Balance +} + +func (a *account) HasStorageAt(key common.Hash) bool { + _, ok := a.Storage[key] + return ok +} + +func (a *account) GetStorageAt(hash common.Hash) common.Hash { + return a.Storage[hash] +} + +func (a *account) GetCode() []byte { + return a.Code +} + +func (a *account) GetStorageSize() int { + return len(a.Storage) +} + +func (a *account) ForEachStorage(h txcontext.StorageHandler) { + for keyHash, valueHash := range a.Storage { + h(keyHash, valueHash) + } +} + +func (a *account) String() string { + return txcontext.AccountString(a) +} diff --git a/txcontext/substate/account_test.go b/txcontext/substate/account_test.go new file mode 100644 index 000000000..9a10e1abb --- /dev/null +++ b/txcontext/substate/account_test.go @@ -0,0 +1,106 @@ +package substate + +import ( + "fmt" + "math/big" + "strings" + "testing" + + "github.com/Fantom-foundation/Aida/txcontext" + substate "github.com/Fantom-foundation/Substate" + "github.com/ethereum/go-ethereum/common" +) + +// TestAccount_EqualNonce tests whether Equal works with nonce. +func TestAccount_EqualNonce(t *testing.T) { + newAccount := substate.NewSubstateAccount(2, new(big.Int).SetUint64(1), []byte{1}) + oldAccount := substate.NewSubstateAccount(1, new(big.Int).SetUint64(1), []byte{1}) + + if txcontext.AccountEqual(NewAccount(newAccount), NewAccount(oldAccount)) { + t.Fatal("accounts nonce are different but equal returned true") + } + + newAccount.Nonce = oldAccount.Nonce + if !txcontext.AccountEqual(NewAccount(newAccount), NewAccount(oldAccount)) { + t.Fatal("accounts nonce are same but equal returned false") + } +} + +// TestAccount_EqualBalance tests whether Equal works with balance. +func TestAccount_EqualBalance(t *testing.T) { + newAccount := substate.NewSubstateAccount(1, new(big.Int).SetUint64(2), []byte{1}) + oldAccount := substate.NewSubstateAccount(1, new(big.Int).SetUint64(1), []byte{1}) + if txcontext.AccountEqual(NewAccount(newAccount), NewAccount(oldAccount)) { + t.Fatal("accounts balances are different but equal returned true") + } + + newAccount.Balance = oldAccount.Balance + if !txcontext.AccountEqual(NewAccount(newAccount), NewAccount(oldAccount)) { + t.Fatal("accounts balances are same but equal returned false") + } +} + +// TestAccount_EqualStorage tests whether Equal works with storage. +func TestAccount_EqualStorage(t *testing.T) { + hashOne := common.BigToHash(new(big.Int).SetUint64(1)) + hashTwo := common.BigToHash(new(big.Int).SetUint64(2)) + hashThree := common.BigToHash(new(big.Int).SetUint64(3)) + + newAccount := substate.NewSubstateAccount(1, new(big.Int).SetUint64(1), []byte{1}) + newAccount.Storage[hashOne] = hashTwo + + // first compare with no storage + oldAccount := substate.NewSubstateAccount(1, new(big.Int).SetUint64(1), []byte{1}) + if txcontext.AccountEqual(NewAccount(newAccount), NewAccount(oldAccount)) { + t.Fatal("accounts storages are different but equal returned true") + } + + // then compare different value for same key + oldAccount.Storage[hashOne] = hashThree + if !txcontext.AccountEqual(NewAccount(newAccount), NewAccount(oldAccount)) { + t.Fatal("accounts storages are same but equal returned false") + } + + // then compare same + oldAccount.Storage[hashOne] = hashTwo + if !txcontext.AccountEqual(NewAccount(newAccount), NewAccount(oldAccount)) { + t.Fatal("accounts storages are different but equal returned true") + } + + // then compare different keys + oldAccount.Storage[hashTwo] = hashThree + if txcontext.AccountEqual(NewAccount(newAccount), NewAccount(oldAccount)) { + t.Fatal("accounts storages are different but equal returned true") + } + +} + +// TestAccount_EqualCode tests whether Equal works with code. +func TestAccount_EqualCode(t *testing.T) { + newAccount := substate.NewSubstateAccount(1, new(big.Int).SetUint64(1), []byte{2}) + oldAccount := substate.NewSubstateAccount(1, new(big.Int).SetUint64(1), []byte{1}) + if txcontext.AccountEqual(NewAccount(newAccount), NewAccount(oldAccount)) { + t.Fatal("accounts codes are different but equal returned true") + } + + newAccount.Code = oldAccount.Code + if !txcontext.AccountEqual(NewAccount(newAccount), NewAccount(oldAccount)) { + t.Fatal("accounts codes are same but equal returned false") + } + +} + +// TestAccount_String tests whether Stringify method works correctly. +func TestAccount_String(t *testing.T) { + hashOne := common.BigToHash(new(big.Int).SetUint64(1)) + hashTwo := common.BigToHash(new(big.Int).SetUint64(2)) + + acc := substate.NewSubstateAccount(1, new(big.Int).SetUint64(1), []byte{1}) + acc.Storage[hashOne] = hashTwo + + got := txcontext.AccountString(NewAccount(acc)) + want := fmt.Sprintf("Account{\n\t\t\tnonce: %d\n\t\t\tbalance %v\n\t\t\tStorage{\n\t\t\t\t%v=%v\n\t\t\t}\n\t\t}", 1, 1, hashOne, hashTwo) + if strings.Compare(got, want) != 0 { + t.Fatalf("strings are different\ngot: %v\nwant: %v", got, want) + } +} diff --git a/txcontext/substate/block_environment.go b/txcontext/substate/block_environment.go new file mode 100644 index 000000000..8d1f8f414 --- /dev/null +++ b/txcontext/substate/block_environment.go @@ -0,0 +1,52 @@ +package substate + +import ( + "math/big" + + "github.com/Fantom-foundation/Aida/txcontext" + substate "github.com/Fantom-foundation/Substate" + "github.com/ethereum/go-ethereum/common" +) + +// Deprecated: This is a workaround before oldSubstate repository is migrated to new structure. +// Use NewSubstateEnv instead. +func NewBlockEnvironment(env *substate.SubstateEnv) txcontext.BlockEnvironment { + return &blockEnvironment{env} +} + +// Deprecated: This is a workaround before oldSubstate repository is migrated to new structure. +// Use substateEnv instead. +type blockEnvironment struct { + *substate.SubstateEnv +} + +func (e *blockEnvironment) GetBlockHash(block uint64) common.Hash { + if e.BlockHashes == nil { + return common.Hash{} + } + return e.BlockHashes[block] +} + +func (e *blockEnvironment) GetCoinbase() common.Address { + return e.Coinbase +} + +func (e *blockEnvironment) GetDifficulty() *big.Int { + return e.Difficulty +} + +func (e *blockEnvironment) GetGasLimit() uint64 { + return e.GasLimit +} + +func (e *blockEnvironment) GetNumber() uint64 { + return e.Number +} + +func (e *blockEnvironment) GetTimestamp() uint64 { + return e.Timestamp +} + +func (e *blockEnvironment) GetBaseFee() *big.Int { + return e.BaseFee +} diff --git a/txcontext/substate/newsubstate/account.go b/txcontext/substate/newsubstate/account.go new file mode 100644 index 000000000..a5aa1bbc9 --- /dev/null +++ b/txcontext/substate/newsubstate/account.go @@ -0,0 +1,53 @@ +package newsubstate + +import ( + "math/big" + + "github.com/Fantom-foundation/Aida/txcontext" + substateCommon "github.com/Fantom-foundation/Substate/geth/common" + "github.com/Fantom-foundation/Substate/substate" + "github.com/ethereum/go-ethereum/common" +) + +func NewAccount(acc *substate.Account) txcontext.Account { + return &account{acc} +} + +type account struct { + *substate.Account +} + +func (a *account) GetNonce() uint64 { + return a.Nonce +} + +func (a *account) GetBalance() *big.Int { + return a.Balance +} + +func (a *account) HasStorageAt(key common.Hash) bool { + _, ok := a.Storage[substateCommon.Hash(key)] + return ok +} + +func (a *account) GetStorageAt(hash common.Hash) common.Hash { + return common.Hash(a.Storage[substateCommon.Hash(hash)]) +} + +func (a *account) GetCode() []byte { + return a.Code +} + +func (a *account) GetStorageSize() int { + return len(a.Storage) +} + +func (a *account) ForEachStorage(h txcontext.StorageHandler) { + for keyHash, valueHash := range a.Storage { + h(common.Hash(keyHash), common.Hash(valueHash)) + } +} + +func (a *account) String() string { + return txcontext.AccountString(a) +} diff --git a/txcontext/substate/newsubstate/block_environment.go b/txcontext/substate/newsubstate/block_environment.go new file mode 100644 index 000000000..ec541e68c --- /dev/null +++ b/txcontext/substate/newsubstate/block_environment.go @@ -0,0 +1,48 @@ +package newsubstate + +import ( + "math/big" + + "github.com/Fantom-foundation/Aida/txcontext" + "github.com/Fantom-foundation/Substate/substate" + "github.com/ethereum/go-ethereum/common" +) + +func NewBlockEnvironment(env *substate.Env) txcontext.BlockEnvironment { + return &blockEnvironment{env} +} + +type blockEnvironment struct { + *substate.Env +} + +func (e *blockEnvironment) GetBlockHash(block uint64) common.Hash { + if e.BlockHashes == nil { + return common.Hash{} + } + return common.Hash(e.BlockHashes[block]) +} + +func (e *blockEnvironment) GetCoinbase() common.Address { + return common.Address(e.Coinbase) +} + +func (e *blockEnvironment) GetDifficulty() *big.Int { + return e.Difficulty +} + +func (e *blockEnvironment) GetGasLimit() uint64 { + return e.GasLimit +} + +func (e *blockEnvironment) GetNumber() uint64 { + return e.Number +} + +func (e *blockEnvironment) GetTimestamp() uint64 { + return e.Timestamp +} + +func (e *blockEnvironment) GetBaseFee() *big.Int { + return e.BaseFee +} diff --git a/txcontext/substate/newsubstate/receipt.go b/txcontext/substate/newsubstate/receipt.go new file mode 100644 index 000000000..6a15297af --- /dev/null +++ b/txcontext/substate/newsubstate/receipt.go @@ -0,0 +1,42 @@ +package newsubstate + +import ( + "github.com/Fantom-foundation/Aida/txcontext" + "github.com/Fantom-foundation/Substate/substate" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// todo logs + +func NewReceipt(res *substate.Result) txcontext.Receipt { + return &receipt{res} +} + +type receipt struct { + *substate.Result +} + +func (r *receipt) GetStatus() uint64 { + return r.Status +} + +func (r *receipt) GetBloom() types.Bloom { + return types.Bloom(r.Bloom) +} + +func (r *receipt) GetLogs() []*types.Log { + panic("how to return without iterating") +} + +func (r *receipt) GetContractAddress() common.Address { + return common.Address(r.ContractAddress) +} + +func (r *receipt) GetGasUsed() uint64 { + return r.GasUsed +} + +func (r *receipt) Equal(y txcontext.Receipt) bool { + return txcontext.ReceiptEqual(r, y) +} diff --git a/txcontext/substate/newsubstate/substate.go b/txcontext/substate/newsubstate/substate.go new file mode 100644 index 000000000..5016ae059 --- /dev/null +++ b/txcontext/substate/newsubstate/substate.go @@ -0,0 +1,44 @@ +package newsubstate + +import ( + "github.com/Fantom-foundation/Aida/txcontext" + "github.com/Fantom-foundation/Substate/substate" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +func NewTxContext(data *substate.Substate) txcontext.TxContext { + return &substateData{data} +} + +type substateData struct { + *substate.Substate +} + +func (t *substateData) GetInputState() txcontext.WorldState { + return NewWorldState(t.InputAlloc) +} + +func (t *substateData) GetOutputState() txcontext.WorldState { + return NewWorldState(t.OutputAlloc) +} + +func (t *substateData) GetBlockEnvironment() txcontext.BlockEnvironment { + return NewBlockEnvironment(t.Env) +} + +func (t *substateData) GetMessage() types.Message { + var list types.AccessList + for _, tuple := range t.Message.AccessList { + var keys []common.Hash + for _, key := range tuple.StorageKeys { + keys = append(keys, common.Hash(key)) + } + list = append(list, types.AccessTuple{Address: common.Address(tuple.Address), StorageKeys: keys}) + } + return types.NewMessage(common.Address(t.Message.From), (*common.Address)(t.Message.To), t.Message.Nonce, t.Message.Value, t.Message.Gas, t.Message.GasPrice, t.Message.GasFeeCap, t.Message.GasTipCap, t.Message.Data, list, !t.Message.CheckNonce) +} + +func (t *substateData) GetReceipt() txcontext.Receipt { + return NewReceipt(t.Result) +} diff --git a/txcontext/substate/newsubstate/world_state.go b/txcontext/substate/newsubstate/world_state.go new file mode 100644 index 000000000..e462f8f22 --- /dev/null +++ b/txcontext/substate/newsubstate/world_state.go @@ -0,0 +1,52 @@ +package newsubstate + +import ( + "github.com/Fantom-foundation/Aida/txcontext" + substateCommon "github.com/Fantom-foundation/Substate/geth/common" + "github.com/Fantom-foundation/Substate/substate" + "github.com/ethereum/go-ethereum/common" +) + +func NewWorldState(alloc substate.Alloc) txcontext.WorldState { + return worldState{alloc: alloc} +} + +type worldState struct { + alloc substate.Alloc +} + +func (a worldState) Has(addr common.Address) bool { + _, ok := a.alloc[substateCommon.Address(addr)] + return ok +} + +func (a worldState) Equal(y txcontext.WorldState) bool { + return txcontext.WorldStateEqual(a, y) +} + +func (a worldState) Get(addr common.Address) txcontext.Account { + acc, ok := a.alloc[substateCommon.Address(addr)] + if !ok { + return nil + } + + return NewAccount(acc) +} + +func (a worldState) ForEachAccount(h txcontext.AccountHandler) { + for addr, acc := range a.alloc { + h(common.Address(addr), NewAccount(acc)) + } +} + +func (a worldState) Len() int { + return len(a.alloc) +} + +func (a worldState) Delete(addr common.Address) { + delete(a.alloc, substateCommon.Address(addr)) +} + +func (a worldState) String() string { + return txcontext.WorldStateString(a) +} diff --git a/txcontext/substate/receipt.go b/txcontext/substate/receipt.go new file mode 100644 index 000000000..eabe294e8 --- /dev/null +++ b/txcontext/substate/receipt.go @@ -0,0 +1,45 @@ +package substate + +import ( + "github.com/Fantom-foundation/Aida/txcontext" + substate "github.com/Fantom-foundation/Substate" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// todo logs + +// Deprecated: This is a workaround before oldSubstate repository is migrated to new structure. +// Use NewSubstateResult instead. +func NewReceipt(res *substate.SubstateResult) txcontext.Receipt { + return &receipt{res} +} + +// Deprecated: This is a workaround before oldSubstate repository is migrated to new structure. +// Use substateResult instead. +type receipt struct { + *substate.SubstateResult +} + +func (r *receipt) GetStatus() uint64 { + return r.Status +} +func (r *receipt) GetBloom() types.Bloom { + return r.Bloom +} + +func (r *receipt) GetLogs() []*types.Log { + return r.Logs +} + +func (r *receipt) GetContractAddress() common.Address { + return r.ContractAddress +} + +func (r *receipt) GetGasUsed() uint64 { + return r.GasUsed +} + +func (r *receipt) Equal(y txcontext.Receipt) bool { + return txcontext.ReceiptEqual(r, y) +} diff --git a/txcontext/substate/receipt_test.go b/txcontext/substate/receipt_test.go new file mode 100644 index 000000000..7ba4821e7 --- /dev/null +++ b/txcontext/substate/receipt_test.go @@ -0,0 +1,85 @@ +package substate + +import ( + "testing" + + "github.com/Fantom-foundation/Aida/txcontext" + substate "github.com/Fantom-foundation/Substate" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// TestReceipt_EqualStatus tests whether Equal works with status. +func TestReceipt_EqualStatus(t *testing.T) { + res := &substate.SubstateResult{Status: 0} + comparedRes := &substate.SubstateResult{Status: 1} + + if txcontext.ReceiptEqual(NewReceipt(res), NewReceipt(comparedRes)) { + t.Fatal("results status are different but equal returned true") + } + + comparedRes.Status = res.Status + if !txcontext.ReceiptEqual(NewReceipt(res), NewReceipt(comparedRes)) { + t.Fatal("results status are same but equal returned false") + } +} + +// TestReceipt_EqualBloom tests whether Equal works with bloom. +func TestReceipt_EqualBloom(t *testing.T) { + res := &substate.SubstateResult{Bloom: types.Bloom{0}} + comparedRes := &substate.SubstateResult{Bloom: types.Bloom{1}} + + if txcontext.ReceiptEqual(NewReceipt(res), NewReceipt(comparedRes)) { + t.Fatal("results Bloom are different but equal returned true") + } + + comparedRes.Bloom = res.Bloom + if !txcontext.ReceiptEqual(NewReceipt(res), NewReceipt(comparedRes)) { + t.Fatal("results Bloom are same but equal returned false") + } +} + +// TestReceipt_EqualLogs tests whether Equal works with logs. +func TestReceipt_EqualLogs(t *testing.T) { + res := &substate.SubstateResult{Logs: []*types.Log{{Address: common.Address{0}}}} + comparedRes := &substate.SubstateResult{Logs: []*types.Log{{Address: common.Address{1}}}} + + if txcontext.ReceiptEqual(NewReceipt(res), NewReceipt(comparedRes)) { + t.Fatal("results Log are different but equal returned true") + } + + comparedRes.Logs = res.Logs + if !txcontext.ReceiptEqual(NewReceipt(res), NewReceipt(comparedRes)) { + t.Fatal("results Log are same but equal returned false") + } +} + +// TestReceipt_EqualContractAddress tests whether Equal works with contract address. +func TestReceipt_EqualContractAddress(t *testing.T) { + res := &substate.SubstateResult{ContractAddress: common.Address{0}} + comparedRes := &substate.SubstateResult{ContractAddress: common.Address{1}} + + if txcontext.ReceiptEqual(NewReceipt(res), NewReceipt(comparedRes)) { + t.Fatal("results ContractAddress are different but equal returned true") + } + + comparedRes.ContractAddress = res.ContractAddress + if !txcontext.ReceiptEqual(NewReceipt(res), NewReceipt(comparedRes)) { + t.Fatal("results ContractAddress are same but equal returned false") + } +} + +// TestReceipt_EqualGasUsed tests whether Equal works with contract has correct format. +func TestReceipt_EqualGasUsed(t *testing.T) { + res := &substate.SubstateResult{GasUsed: 0} + comparedRes := &substate.SubstateResult{GasUsed: 1} + + if txcontext.ReceiptEqual(NewReceipt(res), NewReceipt(comparedRes)) { + t.Fatal("results GasUsed are different but equal returned true") + } + + comparedRes.GasUsed = res.GasUsed + if !txcontext.ReceiptEqual(NewReceipt(res), NewReceipt(comparedRes)) { + t.Fatal("results GasUsed are same but equal returned false") + } +} diff --git a/txcontext/substate/substate.go b/txcontext/substate/substate.go new file mode 100644 index 000000000..92f5a4f13 --- /dev/null +++ b/txcontext/substate/substate.go @@ -0,0 +1,35 @@ +package substate + +import ( + "github.com/Fantom-foundation/Aida/txcontext" + substate "github.com/Fantom-foundation/Substate" + "github.com/ethereum/go-ethereum/core/types" +) + +func NewTxContext(data *substate.Substate) txcontext.TxContext { + return &substateData{data} +} + +type substateData struct { + *substate.Substate +} + +func (t *substateData) GetInputState() txcontext.WorldState { + return NewWorldState(t.InputAlloc) +} + +func (t *substateData) GetOutputState() txcontext.WorldState { + return NewWorldState(t.OutputAlloc) +} + +func (t *substateData) GetBlockEnvironment() txcontext.BlockEnvironment { + return NewBlockEnvironment(t.Env) +} + +func (t *substateData) GetMessage() types.Message { + return t.Message.AsMessage() +} + +func (t *substateData) GetReceipt() txcontext.Receipt { + return NewReceipt(t.Result) +} diff --git a/txcontext/substate/world_state.go b/txcontext/substate/world_state.go new file mode 100644 index 000000000..002a1cd15 --- /dev/null +++ b/txcontext/substate/world_state.go @@ -0,0 +1,56 @@ +package substate + +import ( + "github.com/Fantom-foundation/Aida/txcontext" + oldSubstate "github.com/Fantom-foundation/Substate" + "github.com/ethereum/go-ethereum/common" +) + +// Deprecated: This is a workaround before oldSubstate repository is migrated to new structure. +// Use NewSubstateAlloc instead. +func NewWorldState(alloc oldSubstate.SubstateAlloc) txcontext.WorldState { + return worldState{alloc: alloc} +} + +// Deprecated: This is a workaround before oldSubstate repository is migrated to new structure. +// Use substateAlloc instead. +type worldState struct { + alloc oldSubstate.SubstateAlloc +} + +func (a worldState) Has(addr common.Address) bool { + _, ok := a.alloc[addr] + return ok +} + +func (a worldState) Equal(y txcontext.WorldState) bool { + return txcontext.WorldStateEqual(a, y) +} + +func (a worldState) Get(addr common.Address) txcontext.Account { + acc, ok := a.alloc[addr] + if !ok { + return nil + } + + return NewAccount(acc) + +} + +func (a worldState) ForEachAccount(h txcontext.AccountHandler) { + for addr, acc := range a.alloc { + h(addr, NewAccount(acc)) + } +} + +func (a worldState) Len() int { + return len(a.alloc) +} + +func (a worldState) Delete(addr common.Address) { + delete(a.alloc, addr) +} + +func (a worldState) String() string { + return txcontext.WorldStateString(a) +} diff --git a/txcontext/substate/world_state_test.go b/txcontext/substate/world_state_test.go new file mode 100644 index 000000000..08177666e --- /dev/null +++ b/txcontext/substate/world_state_test.go @@ -0,0 +1,57 @@ +package substate + +import ( + "fmt" + "math/big" + "strings" + "testing" + + "github.com/Fantom-foundation/Aida/txcontext" + substate "github.com/Fantom-foundation/Substate" + "github.com/ethereum/go-ethereum/common" +) + +// TestWorldState_Equal tests whether Equal if Worlds States are same. +func TestWorldState_Equal(t *testing.T) { + ws := substate.SubstateAlloc{common.Address{1}: &substate.SubstateAccount{Nonce: 1, Balance: new(big.Int).SetUint64(1), Code: []byte{1}}} + comparedWorldState := substate.SubstateAlloc{common.Address{1}: &substate.SubstateAccount{Nonce: 1, Balance: new(big.Int).SetUint64(1), Code: []byte{1}}} + + if !txcontext.WorldStateEqual(NewWorldState(ws), NewWorldState(comparedWorldState)) { + t.Fatal("world states are same but equal returned false") + } +} + +// TestWorldState_NotEqual tests whether Equal if Worlds States are not same. +func TestWorldState_NotEqual(t *testing.T) { + ws := substate.SubstateAlloc{common.Address{1}: &substate.SubstateAccount{Nonce: 1, Balance: new(big.Int).SetUint64(1), Code: []byte{1}}} + comparedWorldState := substate.SubstateAlloc{common.Address{2}: &substate.SubstateAccount{Nonce: 1, Balance: new(big.Int).SetUint64(1), Code: []byte{1}}} + + if !txcontext.WorldStateEqual(NewWorldState(ws), NewWorldState(comparedWorldState)) { + t.Fatal("world states are different but equal returned false") + } +} + +// TestWorldState_Equal_DifferentLen tests whether Equal if Worlds States have different len. +func TestWorldState_Equal_DifferentLen(t *testing.T) { + ws := substate.SubstateAlloc{common.Address{1}: &substate.SubstateAccount{Nonce: 1, Balance: new(big.Int).SetUint64(1), Code: []byte{1}}} + comparedWorldState := substate.SubstateAlloc{common.Address{1}: &substate.SubstateAccount{Nonce: 1, Balance: new(big.Int).SetUint64(1), Code: []byte{1}}} + + // add one more acc to alloc + comparedWorldState[common.Address{2}] = &substate.SubstateAccount{Nonce: 1, Balance: new(big.Int).SetUint64(1), Code: []byte{1}} + + if txcontext.WorldStateEqual(NewWorldState(ws), NewWorldState(comparedWorldState)) { + t.Fatal("world states are different but equal returned true") + } +} + +// TestWorldState_String tests whether Stringify method has correct format. +func TestWorldState_String(t *testing.T) { + ws := substate.SubstateAlloc{common.Address{1}: &substate.SubstateAccount{Nonce: 1, Balance: new(big.Int).SetUint64(1), Code: []byte{1}}} + + w := NewWorldState(ws) + got := txcontext.WorldStateString(w) + want := fmt.Sprintf("World State {\n\tsize: %d\n\tAccounts:\n\t\t%x: %v\n}", 1, common.Address{1}, w.Get(common.Address{1}).String()) + if strings.Compare(got, want) != 0 { + t.Fatalf("strings are different \ngot: %v\nwant: %v", got, want) + } +} diff --git a/txcontext/tx_context.go b/txcontext/tx_context.go new file mode 100644 index 000000000..0b3b758d8 --- /dev/null +++ b/txcontext/tx_context.go @@ -0,0 +1,41 @@ +package txcontext + +import "github.com/ethereum/go-ethereum/core/types" + +// TxContext implements all three interfaces necessary for +// Input/Output validation and Transaction execution +type TxContext interface { + InputState + Transaction + OutputState +} + +// InputState represents what is necessary to implement if input validation is required. +type InputState interface { + // GetInputState returns the state of the WorldState BEFORE executing the transaction. + // This is mainly used for confirming that StateDb has correct data before execution. + // And/Or for creating an InMemory StateDb which lifespan is a single transaction. + GetInputState() WorldState +} + +// Transaction represents what is necessary to implement to be able to execute a transaction using the Executor. +type Transaction interface { + // GetBlockEnvironment returns the transaction environment. + // This is used for creating the correct block environment for execution. + GetBlockEnvironment() BlockEnvironment + + // GetMessage returns the message of the transaction. + // Message holds data needed by the EVM to execute the transaction. + GetMessage() types.Message +} + +// OutputState represents what is necessary to implement if output validation is required. +type OutputState interface { + // GetOutputState returns the state of the WorldState AFTER executing the transaction. + // This is mainly used for confirming that StateDb has correct data AFTER execution. + GetOutputState() WorldState + + // GetReceipt returns the Receipt of the transaction. + // This is used for comparing result returned by the StateDb. + GetReceipt() Receipt +} diff --git a/txcontext/world_state.go b/txcontext/world_state.go new file mode 100644 index 000000000..852e98dac --- /dev/null +++ b/txcontext/world_state.go @@ -0,0 +1,80 @@ +package txcontext + +import ( + "fmt" + "sort" + "strings" + + "github.com/ethereum/go-ethereum/common" +) + +// WorldState represents an interface for managing and interacting with a collection of Ethereum-like accounts. +type WorldState interface { + // Get retrieves the account associated with the given address. + // Get should return nil if account is not found. + Get(addr common.Address) Account + + Has(addr common.Address) bool + + // ForEachAccount iterates over each account in the collection and + // invokes the provided AccountHandler function for each account. + ForEachAccount(AccountHandler) + + // Len returns the number of accounts in the collection. + Len() int + + // Equal checks if the current allocation is equal to the provided allocation. + // Two allocations are considered equal if they have the same accounts associated with + // the same addresses. If any account is missing, allocs are considered non-equal. + // Note: Have a look at WorldStateEqual() + Equal(WorldState) bool + + // Delete the record for given address + Delete(addr common.Address) + + // String returns human-readable version of alloc. + // Note: Have a look at WorldStateString() + String() string +} + +type AccountHandler func(addr common.Address, acc Account) + +func WorldStateEqual(x, y WorldState) (isEqual bool) { + if x.Len() != y.Len() { + return false + } + + x.ForEachAccount(func(addr common.Address, acc Account) { + yAcc := y.Get(addr) + if yAcc == nil { + isEqual = false + return + } + + if !AccountEqual(acc, yAcc) { + isEqual = false + return + } + }) + + return true +} + +func WorldStateString(a WorldState) string { + builder := strings.Builder{} + builder.WriteString(fmt.Sprintf("World State {\n\tsize: %d\n", a.Len())) + var addresses []common.Address + + a.ForEachAccount(func(addr common.Address, acc Account) { + addresses = append(addresses, addr) + }) + + sort.Slice(addresses, func(i, j int) bool { return addresses[i].String() < addresses[j].String() }) + + builder.WriteString("\tAccounts:\n") + for _, addr := range addresses { + builder.WriteString(fmt.Sprintf("\t\t%x: %v\n", addr, a.Get(addr).String())) + } + builder.WriteString("}") + return builder.String() +} diff --git a/utildb/gen_deleted_accounts.go b/utildb/gen_deleted_accounts.go index 1e25dc6f3..1d077e986 100644 --- a/utildb/gen_deleted_accounts.go +++ b/utildb/gen_deleted_accounts.go @@ -7,6 +7,7 @@ import ( "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" "github.com/Fantom-foundation/Aida/state/proxy" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" @@ -68,7 +69,9 @@ func genDeletedAccountsTask( ch := make(chan proxy.ContractLiveliness, channelSize) var statedb state.StateDB var err error - statedb, err = state.MakeOffTheChainStateDB(tx.Substate.InputAlloc, tx.Block, state.NewChainConduit(cfg.ChainID == utils.EthereumChainID, utils.GetChainConfig(cfg.ChainID))) + ss := substatecontext.NewTxContext(tx.Substate) + + statedb, err = state.MakeOffTheChainStateDB(ss.GetInputState(), tx.Block, state.NewChainConduit(cfg.ChainID == utils.EthereumChainID, utils.GetChainConfig(cfg.ChainID))) if err != nil { return err } @@ -76,7 +79,7 @@ func genDeletedAccountsTask( //wrapper statedb = proxy.NewDeletionProxy(statedb, ch, cfg.LogLevel) - err = processor.ProcessTransaction(statedb, int(tx.Block), tx.Transaction, tx.Substate) + err = processor.ProcessTransaction(statedb, int(tx.Block), tx.Transaction, ss) if err != nil { return nil } diff --git a/utildb/lachesis-update.go b/utildb/lachesis-update.go index 6ca691edd..288f8a257 100644 --- a/utildb/lachesis-update.go +++ b/utildb/lachesis-update.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/utils" "github.com/Fantom-foundation/Aida/world-state/db/snapshot" substate "github.com/Fantom-foundation/Substate" @@ -32,7 +33,7 @@ func CreateLachesisWorldState(cfg *utils.Config) (substate.SubstateAlloc, error) return nil, err } // remove deleted accounts - if err := utils.DeleteDestroyedAccountsFromWorldState(lachesis, cfg, lachesisLastBlock); err != nil { + if err := utils.DeleteDestroyedAccountsFromWorldState(substatecontext.NewWorldState(lachesis), cfg, lachesisLastBlock); err != nil { return nil, err } return lachesis, nil diff --git a/utils/prime_ctx.go b/utils/prime_ctx.go index 37f390dad..d03327676 100644 --- a/utils/prime_ctx.go +++ b/utils/prime_ctx.go @@ -7,7 +7,7 @@ import ( "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" - substate "github.com/Fantom-foundation/Substate" + "github.com/Fantom-foundation/Aida/txcontext" "github.com/ethereum/go-ethereum/common" ) @@ -41,33 +41,43 @@ func (pc *PrimeContext) mayApplyBulkLoad() error { } // PrimeStateDB primes database with accounts from the world state. -func (pc *PrimeContext) PrimeStateDB(ws substate.SubstateAlloc, db state.StateDB) error { +func (pc *PrimeContext) PrimeStateDB(ws txcontext.WorldState, db state.StateDB) error { numValues := 0 // number of storage values - for _, account := range ws { - numValues += len(account.Storage) - } - pc.log.Infof("\tLoading %d accounts with %d values ..", len(ws), numValues) + ws.ForEachAccount(func(address common.Address, account txcontext.Account) { + numValues += account.GetStorageSize() + }) + + pc.log.Infof("\tLoading %d accounts with %d values ..", ws.Len(), numValues) pt := NewProgressTracker(numValues, pc.log) if pc.cfg.PrimeRandom { //if 0, commit once after priming all accounts if pc.cfg.PrimeThreshold == 0 { - pc.cfg.PrimeThreshold = len(ws) + pc.cfg.PrimeThreshold = ws.Len() } if err := pc.PrimeStateDBRandom(ws, db, pt); err != nil { return fmt.Errorf("failed to prime StateDB: %v", err) } } else { pc.load = db.StartBulkLoad(pc.block) - for addr, account := range ws { - if err := pc.primeOneAccount(addr, account, pt); err != nil { - return err + + var forEachError error + ws.ForEachAccount(func(addr common.Address, acc txcontext.Account) { + if err := pc.primeOneAccount(addr, acc, pt); err != nil { + forEachError = err + return } // commit to stateDB after process n operations if err := pc.mayApplyBulkLoad(); err != nil { - return err + forEachError = err + return } + }) + + if forEachError != nil { + return forEachError } + if err := pc.load.Close(); err != nil { return fmt.Errorf("failed to prime StateDB: %v", err) } @@ -78,34 +88,42 @@ func (pc *PrimeContext) PrimeStateDB(ws substate.SubstateAlloc, db state.StateDB } // primeOneAccount initializes an account on stateDB with substate -func (pc *PrimeContext) primeOneAccount(addr common.Address, account *substate.SubstateAccount, pt *ProgressTracker) error { +func (pc *PrimeContext) primeOneAccount(addr common.Address, acc txcontext.Account, pt *ProgressTracker) error { // if an account was previously primed, skip account creation. if exist, found := pc.exist[addr]; !found || !exist { pc.load.CreateAccount(addr) pc.exist[addr] = true pc.operations++ } - pc.load.SetBalance(addr, account.Balance) - pc.load.SetNonce(addr, account.Nonce) - pc.load.SetCode(addr, account.Code) + pc.load.SetBalance(addr, acc.GetBalance()) + pc.load.SetNonce(addr, acc.GetNonce()) + pc.load.SetCode(addr, acc.GetCode()) pc.operations = pc.operations + 3 - for key, value := range account.Storage { - pc.load.SetState(addr, key, value) + + var forEachError error + acc.ForEachStorage(func(keyHash common.Hash, valueHash common.Hash) { + pc.load.SetState(addr, keyHash, valueHash) pt.PrintProgress() pc.operations++ if err := pc.mayApplyBulkLoad(); err != nil { - return err + forEachError = err + return } + }) + + if forEachError != nil { + return forEachError } + return nil } // PrimeStateDBRandom primes database with accounts from the world state in random order. -func (pc *PrimeContext) PrimeStateDBRandom(ws substate.SubstateAlloc, db state.StateDB, pt *ProgressTracker) error { - contracts := make([]string, 0, len(ws)) - for addr := range ws { +func (pc *PrimeContext) PrimeStateDBRandom(ws txcontext.WorldState, db state.StateDB, pt *ProgressTracker) error { + contracts := make([]string, 0, ws.Len()) + ws.ForEachAccount(func(addr common.Address, _ txcontext.Account) { contracts = append(contracts, addr.Hex()) - } + }) sort.Strings(contracts) // shuffle contract order @@ -117,7 +135,7 @@ func (pc *PrimeContext) PrimeStateDBRandom(ws substate.SubstateAlloc, db state.S pc.load = db.StartBulkLoad(pc.block) for _, c := range contracts { addr := common.HexToAddress(c) - account := ws[addr] + account := ws.Get(addr) if err := pc.primeOneAccount(addr, account, pt); err != nil { return err } diff --git a/utils/statedb.go b/utils/statedb.go index 3fa34408d..73b0871d2 100644 --- a/utils/statedb.go +++ b/utils/statedb.go @@ -8,6 +8,7 @@ import ( "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" "github.com/Fantom-foundation/Aida/state/proxy" + "github.com/Fantom-foundation/Aida/txcontext" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" "github.com/google/martian/log" @@ -204,7 +205,7 @@ func makeStateDBVariant(directory, impl, variant, archiveVariant string, carmenS // DeleteDestroyedAccountsFromWorldState removes previously suicided accounts from // the world state. -func DeleteDestroyedAccountsFromWorldState(ws substate.SubstateAlloc, cfg *Config, target uint64) error { +func DeleteDestroyedAccountsFromWorldState(ws txcontext.WorldState, cfg *Config, target uint64) error { log := logger.NewLogger(cfg.LogLevel, "DelDestAcc") src, err := substate.OpenDestroyedAccountDBReadOnly(cfg.DeletionDb) @@ -217,9 +218,9 @@ func DeleteDestroyedAccountsFromWorldState(ws substate.SubstateAlloc, cfg *Confi return err } for _, cur := range list { - if _, found := ws[cur]; found { + if ws.Has(cur) { log.Debugf("Remove %v from world state", cur) - delete(ws, cur) + ws.Delete(cur) } } return nil diff --git a/utils/statedb_test.go b/utils/statedb_test.go index 9a7c6213d..5d02e0634 100644 --- a/utils/statedb_test.go +++ b/utils/statedb_test.go @@ -10,6 +10,7 @@ import ( "github.com/Fantom-foundation/Aida/logger" "github.com/Fantom-foundation/Aida/state" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" @@ -43,7 +44,8 @@ func TestStatedb_DeleteDestroyedAccountsFromWorldState(t *testing.T) { t.Run(fmt.Sprintf("DB variant: %s; shadowImpl: %s; archive variant: %s", tc.Variant, tc.ShadowImpl, tc.ArchiveVariant), func(t *testing.T) { cfg := MakeTestConfig(tc) // Generating randomized world state - ws, addrList := MakeWorldState(t) + alloc, addrList := MakeWorldState(t) + ws := substatecontext.NewWorldState(alloc) // Init directory for destroyed accounts DB deletionDb := t.TempDir() // Pick two account which will represent destroyed ones @@ -83,7 +85,7 @@ func TestStatedb_DeleteDestroyedAccountsFromWorldState(t *testing.T) { } // check if accounts are not present anymore - if ws[destroyedAccounts[0]] != nil || ws[destroyedAccounts[1]] != nil { + if ws.Get(destroyedAccounts[0]) != nil || ws.Get(destroyedAccounts[1]) != nil { t.Fatalf("failed to delete accounts from the world state") } }) @@ -96,7 +98,8 @@ func TestStatedb_DeleteDestroyedAccountsFromStateDB(t *testing.T) { t.Run(fmt.Sprintf("DB variant: %s; shadowImpl: %s; archive variant: %s", tc.Variant, tc.ShadowImpl, tc.ArchiveVariant), func(t *testing.T) { cfg := MakeTestConfig(tc) // Generating randomized world state - ws, addrList := MakeWorldState(t) + alloc, addrList := MakeWorldState(t) + ws := substatecontext.NewWorldState(alloc) // Init directory for destroyed accounts DB deletedAccountsDir := t.TempDir() // Pick two account which will represent destroyed ones diff --git a/utils/test_cases.go b/utils/test_cases.go index 0a0e43901..1088a3787 100644 --- a/utils/test_cases.go +++ b/utils/test_cases.go @@ -102,7 +102,7 @@ func MakeWorldState(t *testing.T) (substate.SubstateAlloc, []common.Address) { var addrList []common.Address // create world state - ws := substate.SubstateAlloc{} + ws := make(substate.SubstateAlloc) for i := 0; i < 100; i++ { // create random address @@ -111,13 +111,16 @@ func MakeWorldState(t *testing.T) (substate.SubstateAlloc, []common.Address) { // add to address list addrList = append(addrList, addr) - // create account - ws[addr] = &substate.SubstateAccount{ + acc := substate.SubstateAccount{ Nonce: uint64(GetRandom(1, 1000*5000)), Balance: big.NewInt(int64(GetRandom(1, 1000*5000))), Storage: MakeAccountStorage(t), Code: MakeRandomByteSlice(t, 2048), } + ws[addr] = &acc + + // create account + } return ws, addrList diff --git a/utils/worldstate_update.go b/utils/worldstate_update.go index 40d4a5b20..021969250 100644 --- a/utils/worldstate_update.go +++ b/utils/worldstate_update.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + substatecontext "github.com/Fantom-foundation/Aida/txcontext/substate" "github.com/Fantom-foundation/Aida/world-state/db/snapshot" substate "github.com/Fantom-foundation/Substate" "github.com/ethereum/go-ethereum/common" @@ -90,7 +91,7 @@ func GenerateWorldStateFromUpdateDB(cfg *Config, target uint64) (substate.Substa return nil, err } ws.Merge(update) - err = DeleteDestroyedAccountsFromWorldState(ws, cfg, target) + err = DeleteDestroyedAccountsFromWorldState(substatecontext.NewWorldState(ws), cfg, target) return ws, err }