Skip to content

Commit

Permalink
fix: do not run newer migrations on old blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
dessaya committed Mar 1, 2024
1 parent 2804485 commit c8a6bc3
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 14 deletions.
2 changes: 2 additions & 0 deletions packages/chain/cons/cons.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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
}
Expand Down
2 changes: 2 additions & 0 deletions packages/chain/mempool/mempool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down
35 changes: 34 additions & 1 deletion packages/chainutil/runvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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),
Expand All @@ -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 {
Expand All @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions packages/evm/jsonrpc/jsonrpcindex/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions packages/solo/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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)
Expand Down
28 changes: 28 additions & 0 deletions packages/vm/core/migrations/migration.go
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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
}
36 changes: 36 additions & 0 deletions packages/vm/core/migrations/migrations_test.go
Original file line number Diff line number Diff line change
@@ -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))
})
}
12 changes: 1 addition & 11 deletions packages/vm/vmimpl/runtask.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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()
})

Expand Down Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion packages/vm/vmimpl/vmrun_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}

Expand Down
2 changes: 1 addition & 1 deletion packages/vm/vmtask.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down

0 comments on commit c8a6bc3

Please sign in to comment.