diff --git a/packages/chain/cons/cons.go b/packages/chain/cons/cons.go index 510f6182cb..32b05a6862 100644 --- a/packages/chain/cons/cons.go +++ b/packages/chain/cons/cons.go @@ -78,6 +78,7 @@ import ( "github.com/iotaledger/wasp/packages/transaction" "github.com/iotaledger/wasp/packages/util" "github.com/iotaledger/wasp/packages/vm" + "github.com/iotaledger/wasp/packages/vm/core/migrations/allmigrations" "github.com/iotaledger/wasp/packages/vm/processors" ) @@ -565,6 +566,7 @@ func (c *consImpl) uponVMInputsReceived(aggregatedProposals *bp.AggregatedBatchP EstimateGasMode: false, EnableGasBurnLogging: false, Log: c.log.Named("VM"), + Migrations: allmigrations.DefaultScheme, } return nil } diff --git a/packages/chain/mempool/mempool_test.go b/packages/chain/mempool/mempool_test.go index bf00d21cfa..fd92460a3c 100644 --- a/packages/chain/mempool/mempool_test.go +++ b/packages/chain/mempool/mempool_test.go @@ -39,6 +39,7 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/accounts" "github.com/iotaledger/wasp/packages/vm/core/blocklog" "github.com/iotaledger/wasp/packages/vm/core/coreprocessors" + "github.com/iotaledger/wasp/packages/vm/core/migrations/allmigrations" "github.com/iotaledger/wasp/packages/vm/gas" "github.com/iotaledger/wasp/packages/vm/processors" "github.com/iotaledger/wasp/packages/vm/vmimpl" @@ -213,6 +214,7 @@ func blockFn(te *testEnv, reqs []isc.Request, ao *isc.AliasOutputWithID, tangleT EstimateGasMode: false, EnableGasBurnLogging: false, Log: te.log.Named("VM"), + Migrations: allmigrations.DefaultScheme, } vmResult, err := vmimpl.Run(vmTask) require.NoError(te.t, err) diff --git a/packages/chainutil/runvm.go b/packages/chainutil/runvm.go index 2abfda1888..ce67fc08eb 100644 --- a/packages/chainutil/runvm.go +++ b/packages/chainutil/runvm.go @@ -6,11 +6,18 @@ import ( "go.uber.org/zap" + "github.com/samber/lo" + "github.com/iotaledger/wasp/packages/chain" "github.com/iotaledger/wasp/packages/hashing" "github.com/iotaledger/wasp/packages/isc" + "github.com/iotaledger/wasp/packages/state" + "github.com/iotaledger/wasp/packages/state/indexedstore" + "github.com/iotaledger/wasp/packages/transaction" "github.com/iotaledger/wasp/packages/vm" "github.com/iotaledger/wasp/packages/vm/core/accounts" + "github.com/iotaledger/wasp/packages/vm/core/migrations" + "github.com/iotaledger/wasp/packages/vm/core/migrations/allmigrations" "github.com/iotaledger/wasp/packages/vm/vmimpl" ) @@ -22,11 +29,16 @@ func runISCTask( estimateGasMode bool, evmTracer *isc.EVMTracer, ) ([]*vm.RequestResult, error) { + store := ch.Store() + migs, err := getMigrationsForBlock(store, aliasOutput) + if err != nil { + return nil, err + } task := &vm.VMTask{ Processors: ch.Processors(), AnchorOutput: aliasOutput.GetAliasOutput(), AnchorOutputID: aliasOutput.OutputID(), - Store: ch.Store(), + Store: store, Requests: reqs, TimeAssumption: blockTime, Entropy: hashing.PseudoRandomHash(nil), @@ -35,6 +47,7 @@ func runISCTask( EstimateGasMode: estimateGasMode, EVMTracer: evmTracer, Log: ch.Log().Desugar().WithOptions(zap.AddCallerSkip(1)).Sugar(), + Migrations: migs, } res, err := vmimpl.Run(task) if err != nil { @@ -43,6 +56,26 @@ func runISCTask( return res.RequestResults, nil } +func getMigrationsForBlock(store indexedstore.IndexedStore, aliasOutput *isc.AliasOutputWithID) (*migrations.MigrationScheme, error) { + prevL1Commitment, err := transaction.L1CommitmentFromAliasOutput(aliasOutput.GetAliasOutput()) + if err != nil { + panic(err) + } + prevState, err := store.StateByTrieRoot(prevL1Commitment.TrieRoot()) + if err != nil { + if errors.Is(err, state.ErrTrieRootNotFound) { + return allmigrations.DefaultScheme, nil + } + panic(err) + } + if lo.Must(store.LatestBlockIndex()) == prevState.BlockIndex() { + return allmigrations.DefaultScheme, nil + } + newState := lo.Must(store.StateByIndex(prevState.BlockIndex() + 1)) + targetSchemaVersion := newState.SchemaVersion() + return allmigrations.DefaultScheme.WithTargetSchemaVersion(targetSchemaVersion) +} + func runISCRequest( ch chain.ChainCore, aliasOutput *isc.AliasOutputWithID, diff --git a/packages/evm/jsonrpc/jsonrpcindex/index.go b/packages/evm/jsonrpc/jsonrpcindex/index.go index 4565238dab..0d303cc003 100644 --- a/packages/evm/jsonrpc/jsonrpcindex/index.go +++ b/packages/evm/jsonrpc/jsonrpcindex/index.go @@ -67,6 +67,9 @@ func (c *Index) IndexBlock(trieRoot trie.Hash) { if lastBlockIndexed != nil { cacheUntil = *lastBlockIndexed } + if blockIndexToCache <= cacheUntil { + return + } // we need to look at the next block to get the trie commitment of the block we want to cache nextBlockInfo, found := blocklog.NewStateAccess(state).BlockInfo(blockIndexToCache + 1) diff --git a/packages/solo/run.go b/packages/solo/run.go index 7b79d559be..ddc2438ba4 100644 --- a/packages/solo/run.go +++ b/packages/solo/run.go @@ -20,6 +20,7 @@ import ( "github.com/iotaledger/wasp/packages/transaction" "github.com/iotaledger/wasp/packages/vm" "github.com/iotaledger/wasp/packages/vm/core/blocklog" + "github.com/iotaledger/wasp/packages/vm/core/migrations/allmigrations" "github.com/iotaledger/wasp/packages/vm/vmimpl" ) @@ -68,6 +69,7 @@ func (ch *Chain) runTaskNoLock(reqs []isc.Request, estimateGas bool) *vm.VMTaskR // state baseline is always valid in Solo EnableGasBurnLogging: ch.Env.enableGasBurnLogging, EstimateGasMode: estimateGas, + Migrations: allmigrations.DefaultScheme, } res, err := vmimpl.Run(task) diff --git a/packages/vm/core/migrations/migration.go b/packages/vm/core/migrations/migration.go index 0023372343..d1fde98ffb 100644 --- a/packages/vm/core/migrations/migration.go +++ b/packages/vm/core/migrations/migration.go @@ -1,6 +1,9 @@ package migrations import ( + "errors" + "fmt" + "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/wasp/packages/isc" "github.com/iotaledger/wasp/packages/isc/coreutil" @@ -20,3 +23,28 @@ type MigrationScheme struct { func (m *MigrationScheme) LatestSchemaVersion() isc.SchemaVersion { return m.BaseSchemaVersion + isc.SchemaVersion(len(m.Migrations)) } + +var ( + ErrMissingMigrationCode = errors.New("missing migration code for target schema version") + ErrInvalidSchemaVersion = errors.New("invalid schema version") +) + +// WithTargetSchemaVersion returns a new MigrationScheme where all migrations +// that correspond to a schema version newer than v are removed. +// This is necessary in order to replay old blocks without applying the newer migrations. +func (m *MigrationScheme) WithTargetSchemaVersion(v isc.SchemaVersion) (*MigrationScheme, error) { + newMigrations := m.Migrations + if len(newMigrations) > 0 { + if v < m.BaseSchemaVersion { + return nil, fmt.Errorf("cannot determine migration scheme for target schema version %d: %w", v, ErrMissingMigrationCode) + } + if v > m.LatestSchemaVersion() { + return nil, fmt.Errorf("cannot determine migration scheme for target schema version %d: %w", v, ErrInvalidSchemaVersion) + } + newMigrations = newMigrations[:v-m.BaseSchemaVersion] + } + return &MigrationScheme{ + BaseSchemaVersion: m.BaseSchemaVersion, + Migrations: newMigrations, + }, nil +} diff --git a/packages/vm/core/migrations/migrations_test.go b/packages/vm/core/migrations/migrations_test.go new file mode 100644 index 0000000000..782d3264a9 --- /dev/null +++ b/packages/vm/core/migrations/migrations_test.go @@ -0,0 +1,36 @@ +package migrations + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMigrationScheme_WithTargetSchemaVersion(t *testing.T) { + scheme := &MigrationScheme{ + BaseSchemaVersion: 3, + Migrations: []Migration{ + {}, // 4 + {}, // 5 + }, + } + + t.Run("ok", func(t *testing.T) { + newScheme, err := scheme.WithTargetSchemaVersion(4) + require.NoError(t, err) + require.EqualValues(t, 4, newScheme.LatestSchemaVersion()) + }) + + t.Run("missing migration code", func(t *testing.T) { + _, err := scheme.WithTargetSchemaVersion(2) + require.Error(t, err) + require.True(t, errors.Is(err, ErrMissingMigrationCode)) + }) + + t.Run("invalid schema version", func(t *testing.T) { + _, err := scheme.WithTargetSchemaVersion(6) + require.Error(t, err) + require.True(t, errors.Is(err, ErrInvalidSchemaVersion)) + }) +} diff --git a/packages/vm/vmimpl/runtask.go b/packages/vm/vmimpl/runtask.go index b839314744..1a3efc1d9e 100644 --- a/packages/vm/vmimpl/runtask.go +++ b/packages/vm/vmimpl/runtask.go @@ -16,8 +16,6 @@ import ( "github.com/iotaledger/wasp/packages/vm/core/accounts" "github.com/iotaledger/wasp/packages/vm/core/blocklog" "github.com/iotaledger/wasp/packages/vm/core/governance" - "github.com/iotaledger/wasp/packages/vm/core/migrations" - "github.com/iotaledger/wasp/packages/vm/core/migrations/allmigrations" "github.com/iotaledger/wasp/packages/vm/core/root" "github.com/iotaledger/wasp/packages/vm/vmexceptions" "github.com/iotaledger/wasp/packages/vm/vmtxbuilder" @@ -107,8 +105,7 @@ func (vmctx *vmContext) init(prevL1Commitment *state.L1Commitment) { vmctx.loadChainConfig() vmctx.withStateUpdate(func(chainState kv.KVStore) { - migrationScheme := vmctx.getMigrations() - vmctx.runMigrations(chainState, migrationScheme) + vmctx.runMigrations(chainState, vmctx.task.Migrations) vmctx.schemaVersion = root.NewStateAccess(chainState).SchemaVersion() }) @@ -144,13 +141,6 @@ func (vmctx *vmContext) init(prevL1Commitment *state.L1Commitment) { ) } -func (vmctx *vmContext) getMigrations() *migrations.MigrationScheme { - if vmctx.task.MigrationsOverride != nil { - return vmctx.task.MigrationsOverride - } - return allmigrations.DefaultScheme -} - func (vmctx *vmContext) getAnchorOutputSD() uint64 { // get the total L2 funds in accounting totalL2Funds := vmctx.loadTotalFungibleTokens() diff --git a/packages/vm/vmimpl/vmrun_test.go b/packages/vm/vmimpl/vmrun_test.go index 8346fa35f3..522b1388b4 100644 --- a/packages/vm/vmimpl/vmrun_test.go +++ b/packages/vm/vmimpl/vmrun_test.go @@ -103,7 +103,7 @@ func simulateRunOutput(t *testing.T, output iotago.Output) *vm.VMTaskResult { EstimateGasMode: false, EVMTracer: &isc.EVMTracer{}, EnableGasBurnLogging: false, - MigrationsOverride: &migrations.MigrationScheme{}, + Migrations: &migrations.MigrationScheme{}, Log: testlogger.NewLogger(t), } diff --git a/packages/vm/vmtask.go b/packages/vm/vmtask.go index 63c04b4793..d9fd9e2ef2 100644 --- a/packages/vm/vmtask.go +++ b/packages/vm/vmtask.go @@ -33,7 +33,7 @@ type VMTask struct { EVMTracer *isc.EVMTracer EnableGasBurnLogging bool // for testing and Solo only - MigrationsOverride *migrations.MigrationScheme // for testing and Solo only + Migrations *migrations.MigrationScheme // for testing and Solo only Log *logger.Logger }