Skip to content

Commit

Permalink
Add vm-sdb protobuf support
Browse files Browse the repository at this point in the history
  • Loading branch information
matejmode committed Nov 1, 2024
1 parent 7bddcf6 commit 7bca5f0
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 31 deletions.
2 changes: 2 additions & 0 deletions cmd/aida-vm-sdb/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,13 @@ var RunSubstateCmd = cli.Command{
//&utils.MaxNumTransactionsFlag,
&utils.ValidateTxStateFlag,
&utils.ValidateFlag,
&utils.UpdateOnFailure,
&logger.LogLevelFlag,
&utils.NoHeartbeatLoggingFlag,
&utils.TrackProgressFlag,
&utils.ErrorLoggingFlag,
&utils.TrackerGranularityFlag,
&utils.SubstateEncodingFlag,
},
Description: `
The aida-vm-sdb substate command requires two arguments: <blockNumFirst> <blockNumLast>
Expand Down
2 changes: 2 additions & 0 deletions cmd/aida-vm-sdb/run_substate.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ func runSubstates(cfg *utils.Config, provider executor.Provider[txcontext.TxCont
validator.MakeStateHashValidator[txcontext.TxContext](cfg),
statedb.MakeBlockEventEmitter[txcontext.TxContext](),
statedb.MakeTransactionEventEmitter[txcontext.TxContext](),
validator.MakeEthereumDbPreTransactionUpdator(cfg),
validator.MakeLiveDbValidator(cfg, validator.ValidateTxTarget{WorldState: true, Receipt: true}),
validator.MakeEthereumDbPostTransactionUpdator(cfg),
profiler.MakeOperationProfiler[txcontext.TxContext](cfg),

// block profile extension should be always last because:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,80 @@ func TestEthStateTestValidator_PostBlockChecksError(t *testing.T) {
})
}
}

func TestEthStateTestValidator_PreBlockEthereumReturnsSuccessBalanceFix(t *testing.T) {
cfg := &utils.Config{}
cfg.ContinueOnFailure = true
cfg.ChainID = 1
cfg.UpdateOnFailure = "all"

ctrl := gomock.NewController(t)
log := logger.NewMockLogger(ctrl)
db := state.NewMockStateDB(ctrl)

data := ethtest.CreateTestTransaction(t)
ctx := new(executor.Context)
ctx.State = db
st := executor.State[txcontext.TxContext]{Block: 1, Transaction: 1, Data: data}

gomock.InOrder(
db.EXPECT().Exist(common.HexToAddress("0x1")).Return(true),
// incorrect balance value is fixed
db.EXPECT().GetBalance(gomock.Any()).Return(uint256.NewInt(10)),
db.EXPECT().SubBalance(gomock.Any(), uint256.NewInt(10), gomock.Any()),
db.EXPECT().AddBalance(gomock.Any(), uint256.NewInt(1000), gomock.Any()),
db.EXPECT().GetNonce(common.HexToAddress("0x1")).Return(uint64(1)),
db.EXPECT().GetCode(common.HexToAddress("0x1")),
)

gomock.InOrder(
db.EXPECT().Exist(common.HexToAddress("0x2")).Return(true),
db.EXPECT().GetBalance(gomock.Any()).Return(uint256.NewInt(2000)),
db.EXPECT().GetNonce(common.HexToAddress("0x2")).Return(uint64(2)),
db.EXPECT().GetCode(common.HexToAddress("0x2")),
)

ext := makeEthStateTestErrorValidator(cfg, log)
err := ext.PreBlock(st, ctx)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}

func TestEthStateTestValidator_PreBlockEthereumReturnsErrorOverflowingBalanceNotFixed(t *testing.T) {
cfg := &utils.Config{}
cfg.ContinueOnFailure = true
cfg.ChainID = 1
cfg.UpdateOnFailure = "all"

ctrl := gomock.NewController(t)
log := logger.NewMockLogger(ctrl)
db := state.NewMockStateDB(ctrl)

data := ethtest.CreateTestTransaction(t)
ctx := new(executor.Context)
ctx.State = db
st := executor.State[txcontext.TxContext]{Block: 1, Transaction: 1, Data: data}

gomock.InOrder(
db.EXPECT().Exist(common.HexToAddress("0x1")).Return(true),
// incorrect balance value is fixed
db.EXPECT().GetBalance(gomock.Any()).Return(uint256.NewInt(1001)),
db.EXPECT().GetNonce(common.HexToAddress("0x1")).Return(uint64(1)),
db.EXPECT().GetCode(common.HexToAddress("0x1")),
)

gomock.InOrder(
db.EXPECT().Exist(common.HexToAddress("0x2")).Return(true),
db.EXPECT().GetBalance(gomock.Any()).Return(uint256.NewInt(2000)),
db.EXPECT().GetNonce(common.HexToAddress("0x2")).Return(uint64(2)),
db.EXPECT().GetCode(common.HexToAddress("0x2")),
)

wantError := fmt.Errorf("pre alloc validation failed; Failed to validate balance for account 0x0000000000000000000000000000000000000001\n have 1001\n want 1000\n")
ext := makeEthStateTestErrorValidator(cfg, log)
err := ext.PreBlock(st, ctx)
if !strings.Contains(err.Error(), wantError.Error()) {
t.Errorf("unexpected error;\ngot: %v\nwant: %v", err, wantError)
}
}
61 changes: 61 additions & 0 deletions executor/extension/validator/ethereum_post_transaction_updator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2024 Fantom Foundation
// This file is part of Aida Testing Infrastructure for Sonic
//
// Aida is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Aida is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Aida. If not, see <http://www.gnu.org/licenses/>.

package validator

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"
)

// MakeEthereumDbPostTransactionUpdator creates an extension which fixes Ethereum exceptions in LiveDB
func MakeEthereumDbPostTransactionUpdator(cfg *utils.Config) executor.Extension[txcontext.TxContext] {
if cfg.ChainID != utils.EthereumChainID {
return extension.NilExtension[txcontext.TxContext]{}
}

log := logger.NewLogger(cfg.LogLevel, "Ethereum-Exception-Updator")

return makeEthereumDbPostTransactionUpdator(cfg, log)
}

func makeEthereumDbPostTransactionUpdator(cfg *utils.Config, log logger.Logger) executor.Extension[txcontext.TxContext] {
return &ethereumDbPostTransactionUpdater{
cfg: cfg,
log: log,
}
}

// PostTransaction fixes OutputAlloc ethereum exceptions in given substate
func (v *ethereumDbPostTransactionUpdater) PostTransaction(state executor.State[txcontext.TxContext], ctx *executor.Context) error {
return updateEthereumDb(state, ctx.State, false)
}

type ethereumDbPostTransactionUpdater struct {
extension.NilExtension[txcontext.TxContext]
cfg *utils.Config
log logger.Logger
}

// PreRun informs the user that ethereumExceptionUpdator is enabled.
func (v *ethereumDbPostTransactionUpdater) PreRun(executor.State[txcontext.TxContext], *executor.Context) error {
v.log.Warning("Ethereum exception post transaction updator is enabled.")

return nil
}
61 changes: 61 additions & 0 deletions executor/extension/validator/ethereum_pre_transaction_updator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2024 Fantom Foundation
// This file is part of Aida Testing Infrastructure for Sonic
//
// Aida is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Aida is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Aida. If not, see <http://www.gnu.org/licenses/>.

package validator

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"
)

// MakeEthereumDbPreTransactionUpdator creates an extension which fixes Ethereum exceptions in pre transaction in LiveDB
func MakeEthereumDbPreTransactionUpdator(cfg *utils.Config) executor.Extension[txcontext.TxContext] {
if cfg.ChainID != utils.EthereumChainID {
return extension.NilExtension[txcontext.TxContext]{}
}

log := logger.NewLogger(cfg.LogLevel, "Ethereum-Exception-Updator")

return makeEthereumDbPreTransactionUpdator(cfg, log)
}

func makeEthereumDbPreTransactionUpdator(cfg *utils.Config, log logger.Logger) executor.Extension[txcontext.TxContext] {
return &ethereumDbPreTransactionUpdator{
cfg: cfg,
log: log,
}
}

// PreTransaction validates fixes InputSubstate ethereum exceptions in given substate
func (v *ethereumDbPreTransactionUpdator) PreTransaction(state executor.State[txcontext.TxContext], ctx *executor.Context) error {
return updateEthereumDb(state, ctx.State, true)
}

type ethereumDbPreTransactionUpdator struct {
extension.NilExtension[txcontext.TxContext]
cfg *utils.Config
log logger.Logger
}

// PreRun informs the user that ethereumExceptionUpdator is enabled.
func (v *ethereumDbPreTransactionUpdator) PreRun(executor.State[txcontext.TxContext], *executor.Context) error {
v.log.Warning("Ethereum exception pre transaction updator is enabled.")

return nil
}
15 changes: 11 additions & 4 deletions executor/extension/validator/transaction_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package validator

import (
"fmt"
"strings"
"sync/atomic"

"github.com/Fantom-foundation/Aida/executor"
Expand Down Expand Up @@ -133,9 +134,13 @@ func (v *stateDbValidator) runPreTxValidation(tool string, db state.VmStateDB, s
return nil
}

err := validateWorldState(v.cfg, db, state.Data.GetInputState(), v.log)
if err == nil {
return nil
var err error
if strings.ToLower(v.cfg.UpdateOnFailure) == "all" || strings.ToLower(v.cfg.UpdateOnFailure) == "pre" {
return updateWorldState(v.cfg, db, state.Data.GetInputState())
} else {
if err = validateWorldState(v.cfg, db, state.Data.GetInputState(), v.log); err == nil {
return nil
}
}

err = fmt.Errorf("%v err:\nblock %v tx %v\n world-state input is not contained in the state-db\n %v\n", tool, state.Block, state.Transaction, err)
Expand All @@ -149,7 +154,9 @@ func (v *stateDbValidator) runPreTxValidation(tool string, db state.VmStateDB, s

func (v *stateDbValidator) runPostTxValidation(tool string, db state.VmStateDB, state executor.State[txcontext.TxContext], res txcontext.Result, errOutput chan error) error {
if v.target.WorldState {
if err := validateWorldState(v.cfg, db, state.Data.GetOutputState(), v.log); err != nil {
if strings.ToLower(v.cfg.UpdateOnFailure) == "all" || strings.ToLower(v.cfg.UpdateOnFailure) == "post" {
return updateWorldState(v.cfg, db, state.Data.GetOutputState())
} else if err := validateWorldState(v.cfg, db, state.Data.GetOutputState(), v.log); err != nil {
err = fmt.Errorf("%v err:\nworld-state output error at block %v tx %v; %v", tool, state.Block, state.Transaction, err)
if v.isErrFatal(err, errOutput) {
return err
Expand Down
4 changes: 2 additions & 2 deletions executor/extension/validator/transaction_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,7 @@ func TestValidateStateDb_ValidationDoesNotFail(t *testing.T) {
}

// Call for state DB validation and subsequent check for error
err = doSubsetValidation(ws, sDB, false)
err = doSubsetValidation(ws, sDB)
if err != nil {
t.Fatalf("failed to validate state DB: %v", err)
}
Expand Down Expand Up @@ -884,7 +884,7 @@ func TestValidateStateDb_ValidationDoesNotFailWithPriming(t *testing.T) {
}

// Call for state DB validation with update enabled and subsequent checks if the update was made correctly
err = doSubsetValidation(ws, sDB, true)
err = doSubsetValidation(ws, sDB)
if err == nil {
t.Fatalf("failed to throw errors while validating state DB: %v", err)
}
Expand Down
Loading

0 comments on commit 7bca5f0

Please sign in to comment.