create function for migrating builtin actors with only code changes
This commit is contained in:
parent
5c0f2c8ae6
commit
339692cde5
@ -868,6 +868,11 @@ workflows:
|
||||
suite: itest-get_messages_in_ts
|
||||
target: "./itests/get_messages_in_ts_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-lite_migration
|
||||
suite: itest-lite_migration
|
||||
target: "./itests/lite_migration_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-lookup_robust_address
|
||||
suite: itest-lookup_robust_address
|
||||
|
@ -5,13 +5,7 @@ import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/v8/actors/migration/nv16"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/v6/actors/migration/nv14"
|
||||
"github.com/filecoin-project/specs-actors/v7/actors/migration/nv15"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"golang.org/x/xerrors"
|
||||
@ -19,9 +13,11 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/manifest"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/go-state-types/rt"
|
||||
|
||||
system8 "github.com/filecoin-project/go-state-types/builtin/v8/system"
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
@ -33,12 +29,18 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/v3/actors/migration/nv10"
|
||||
"github.com/filecoin-project/specs-actors/v4/actors/migration/nv12"
|
||||
"github.com/filecoin-project/specs-actors/v5/actors/migration/nv13"
|
||||
"github.com/filecoin-project/specs-actors/v6/actors/migration/nv14"
|
||||
"github.com/filecoin-project/specs-actors/v7/actors/migration/nv15"
|
||||
"github.com/filecoin-project/specs-actors/v8/actors/migration/nv16"
|
||||
states8 "github.com/filecoin-project/specs-actors/v8/actors/states"
|
||||
adt8 "github.com/filecoin-project/specs-actors/v8/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/system"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@ -1431,6 +1433,157 @@ func upgradeActorsV8Common(
|
||||
return newRoot, nil
|
||||
}
|
||||
|
||||
func UpgradeActorsCode(ctx context.Context, sm *stmgr.StateManager, newActorsManifestCid cid.Cid, root cid.Cid) (cid.Cid, error) {
|
||||
bstore := sm.ChainStore().StateBlockstore()
|
||||
return LiteMigration(ctx, bstore, newActorsManifestCid, root)
|
||||
}
|
||||
|
||||
func LiteMigration(ctx context.Context, bstore blockstore.Blockstore, newActorsManifestCid cid.Cid, root cid.Cid) (cid.Cid, error) {
|
||||
buf := blockstore.NewTieredBstore(bstore, blockstore.NewMemorySync())
|
||||
store := store.ActorStore(ctx, buf)
|
||||
adtStore := adt8.WrapStore(ctx, store)
|
||||
|
||||
// Load the state root.
|
||||
var stateRoot types.StateRoot
|
||||
if err := store.Get(ctx, root, &stateRoot); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to decode state root: %w", err)
|
||||
}
|
||||
|
||||
if stateRoot.Version != types.StateTreeVersion4 {
|
||||
return cid.Undef, xerrors.Errorf(
|
||||
"expected state root version 4 for actors code upgrade, got %d",
|
||||
stateRoot.Version,
|
||||
)
|
||||
}
|
||||
|
||||
// Get old actors
|
||||
actorsIn, err := states8.LoadTree(adtStore, stateRoot.Actors)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to load state tree: %w", err)
|
||||
}
|
||||
systemActor, ok, err := actorsIn.GetActor(system.Address)
|
||||
if !ok {
|
||||
return cid.Undef, xerrors.Errorf("failed to get system actor: %w", err)
|
||||
}
|
||||
systemActorType := types.Actor{
|
||||
Code: systemActor.Code,
|
||||
Head: systemActor.Head,
|
||||
Nonce: systemActor.CallSeqNum,
|
||||
Balance: systemActor.Balance,
|
||||
}
|
||||
systemActorState, err := system.Load(store, &systemActorType)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to load system actor state: %w", err)
|
||||
}
|
||||
oldActorsManifestCid := systemActorState.GetBuiltinActors()
|
||||
|
||||
// load old manifest
|
||||
oldManifest := manifest.Manifest{
|
||||
Version: 1,
|
||||
Data: oldActorsManifestCid,
|
||||
}
|
||||
if err := oldManifest.Load(ctx, adtStore); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("error loading old actor manifest: %w", err)
|
||||
}
|
||||
|
||||
// load new manifest
|
||||
newManifest := manifest.Manifest{}
|
||||
if err := store.Get(ctx, newActorsManifestCid, &newManifest); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("error loading new manifest: %w", err)
|
||||
}
|
||||
newManifestData := manifest.ManifestData{}
|
||||
if err := store.Get(ctx, newManifest.Data, &newManifestData); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("error loading new manifest data: %w", err)
|
||||
}
|
||||
|
||||
// Maps prior version code CIDs to migration functions.
|
||||
migrations := make(map[cid.Cid]cid.Cid)
|
||||
|
||||
for _, entry := range newManifestData.Entries {
|
||||
oldCodeCid, ok := oldManifest.Get(entry.Name)
|
||||
if !ok {
|
||||
return cid.Undef, xerrors.Errorf("code cid for %s actor not found in manifest", entry.Name)
|
||||
}
|
||||
migrations[oldCodeCid] = entry.Code
|
||||
}
|
||||
|
||||
if len(migrations) != 11 {
|
||||
return cid.Undef, xerrors.Errorf("incomplete manifest with %d code CIDs", len(migrations))
|
||||
}
|
||||
startTime := time.Now()
|
||||
|
||||
// Load output state tree
|
||||
actorsOut, err := states8.NewTree(adtStore)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
// Insert migrated records in output state tree.
|
||||
err = actorsIn.ForEach(func(addr address.Address, actorIn *states8.Actor) error {
|
||||
var newActor states8.Actor
|
||||
newCid, ok := migrations[actorIn.Code]
|
||||
if !ok {
|
||||
return xerrors.Errorf("new code cid for system actor not found in migrations for actor %s", addr)
|
||||
}
|
||||
if addr == system.Address {
|
||||
newSystemState := system8.State{BuiltinActors: newManifest.Data}
|
||||
systemStateHead, err := store.Put(ctx, &newSystemState)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not set system actor state head: %w", err)
|
||||
}
|
||||
newActor = states8.Actor{
|
||||
Code: newCid,
|
||||
Head: systemStateHead,
|
||||
CallSeqNum: actorIn.CallSeqNum,
|
||||
Balance: actorIn.Balance,
|
||||
}
|
||||
} else {
|
||||
newActor = states8.Actor{
|
||||
Code: newCid,
|
||||
Head: actorIn.Head,
|
||||
CallSeqNum: actorIn.CallSeqNum,
|
||||
Balance: actorIn.Balance,
|
||||
}
|
||||
}
|
||||
err = actorsOut.SetActor(addr, &newActor)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not set actor at address %s: %w", addr, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
elapsed := time.Since(startTime)
|
||||
log.Infof("All done after %v. Flushing state tree root.", elapsed)
|
||||
newHamtRoot, err := actorsOut.Flush()
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to flush new actors: %w", err)
|
||||
}
|
||||
|
||||
// Persist the result.
|
||||
newRoot, err := store.Put(ctx, &types.StateRoot{
|
||||
Version: types.StateTreeVersion4,
|
||||
Actors: newHamtRoot,
|
||||
Info: stateRoot.Info,
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to persist new state root: %w", err)
|
||||
}
|
||||
|
||||
// Persist the new tree.
|
||||
|
||||
{
|
||||
from := buf
|
||||
to := buf.Read()
|
||||
|
||||
if err := vm.Copy(ctx, from, to, newRoot); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("copying migrated tree: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return newRoot, nil
|
||||
}
|
||||
|
||||
type migrationLogger struct{}
|
||||
|
||||
func (ml migrationLogger) Log(level rt.LogLevel, msg string, args ...interface{}) {
|
||||
|
102
itests/lite_migration_test.go
Normal file
102
itests/lite_migration_test.go
Normal file
@ -0,0 +1,102 @@
|
||||
package itests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/system"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
|
||||
"github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/manifest"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/specs-actors/v8/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/itests/kit"
|
||||
)
|
||||
|
||||
func TestLiteMigration(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
kit.QuietMiningLogs()
|
||||
|
||||
client16, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.GenesisNetworkVersion(network.Version16))
|
||||
ens.InterconnectAll().BeginMining(10 * time.Millisecond)
|
||||
|
||||
client16.WaitTillChain(ctx, func(set *types.TipSet) bool {
|
||||
return set.Height() > 100
|
||||
})
|
||||
|
||||
bs := blockstore.NewAPIBlockstore(client16)
|
||||
ctxStore := adt.WrapBlockStore(ctx, bs)
|
||||
|
||||
ts, err := client16.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
stateRoot := ts.ParentState()
|
||||
newManifestCid := makeTestManifest(t, ctxStore)
|
||||
|
||||
newStateRoot, err := filcns.LiteMigration(ctx, bs, newManifestCid, stateRoot)
|
||||
require.NoError(t, err)
|
||||
|
||||
stateTree, err := state.LoadStateTree(ctxStore, newStateRoot)
|
||||
require.NoError(t, err)
|
||||
|
||||
systemActor, err := stateTree.GetActor(system.Address)
|
||||
|
||||
var newManifest manifest.Manifest
|
||||
err = ctxStore.Get(ctx, newManifestCid, &newManifest)
|
||||
require.NoError(t, err)
|
||||
err = newManifest.Load(ctx, ctxStore)
|
||||
require.NoError(t, err)
|
||||
manifestSystemCodeCid, ok := newManifest.Get("system")
|
||||
require.True(t, ok)
|
||||
|
||||
require.Equal(t, systemActor.Code, manifestSystemCodeCid)
|
||||
|
||||
}
|
||||
|
||||
func makeTestManifest(t *testing.T, ctxStore adt.Store) cid.Cid {
|
||||
builder := cid.V1Builder{Codec: cid.Raw, MhType: mh.IDENTITY}
|
||||
|
||||
manifestData := manifest.ManifestData{}
|
||||
for _, name := range []string{"system", "init", "cron", "account", "storagepower", "storageminer", "storagemarket", "paymentchannel", "multisig", "reward", "verifiedregistry"} {
|
||||
codeCid, err := builder.Sum([]byte(fmt.Sprintf("fil/8/%s", name)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
manifestData.Entries = append(manifestData.Entries,
|
||||
manifest.ManifestEntry{
|
||||
Name: name,
|
||||
Code: codeCid,
|
||||
})
|
||||
}
|
||||
|
||||
manifestDataCid, err := ctxStore.Put(ctxStore.Context(), &manifestData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mf := manifest.Manifest{
|
||||
Version: 1,
|
||||
Data: manifestDataCid,
|
||||
}
|
||||
|
||||
manifestCid, err := ctxStore.Put(ctxStore.Context(), &mf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return manifestCid
|
||||
}
|
Loading…
Reference in New Issue
Block a user