Merge pull request #8815 from filecoin-project/gstuart/lite-migration

feat: migrations: function for migrating builtin actors with only code changes
This commit is contained in:
Aayush Rajasekaran 2022-06-10 15:36:05 -04:00 committed by GitHub
commit b6a7e0553e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 586 additions and 30 deletions

View File

@ -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

View File

@ -6,6 +6,7 @@ import (
"fmt"
"time"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p-core/peer"
@ -38,6 +39,7 @@ import (
type ChainIO interface {
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainHasObj(context.Context, cid.Cid) (bool, error)
ChainPutObj(context.Context, blocks.Block) error
}
const LookbackNoLimit = abi.ChainEpoch(-1)
@ -123,6 +125,9 @@ type FullNode interface {
// ChainHasObj checks if a given CID exists in the chain blockstore.
ChainHasObj(context.Context, cid.Cid) (bool, error) //perm:read
// ChainPutObj puts a given object into the block store
ChainPutObj(context.Context, blocks.Block) error //perm:admin
// ChainStatObj returns statistics about the graph referenced by 'obj'.
// If 'base' is also specified, then the returned stat will be a diff
// between the two objects.

View File

@ -3,6 +3,7 @@ package api
import (
"context"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-address"
@ -30,6 +31,7 @@ import (
type Gateway interface {
ChainHasObj(context.Context, cid.Cid) (bool, error)
ChainPutObj(context.Context, blocks.Block) error
ChainHead(ctx context.Context) (*types.TipSet, error)
ChainGetParentMessages(context.Context, cid.Cid) ([]Message, error)
ChainGetParentReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error)

View File

@ -28,6 +28,7 @@ import (
filestore "github.com/filecoin-project/go-fil-markets/filestore"
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
"github.com/filecoin-project/go-jsonrpc/auth"
blocks "github.com/ipfs/go-block-format"
textselector "github.com/ipld/go-ipld-selector-text-lite"
"github.com/filecoin-project/go-state-types/abi"
@ -95,6 +96,9 @@ func init() {
apiSelExample := api.Selector("Links/21/Hash/Links/42/Hash")
clientEvent := retrievalmarket.ClientEventDealAccepted
block := blocks.Block(&blocks.BasicBlock{})
ExampleValues[reflect.TypeOf(&block).Elem()] = block
addExample(bitfield.NewFromSet([]uint64{5}))
addExample(abi.RegisteredSealProof_StackedDrg32GiBV1_1)
addExample(abi.RegisteredPoStProof_StackedDrgWindow32GiBV1)

View File

@ -31,6 +31,7 @@ import (
imports "github.com/filecoin-project/lotus/node/repo/imports"
gomock "github.com/golang/mock/gomock"
uuid "github.com/google/uuid"
blocks "github.com/ipfs/go-block-format"
cid "github.com/ipfs/go-cid"
metrics "github.com/libp2p/go-libp2p-core/metrics"
network0 "github.com/libp2p/go-libp2p-core/network"
@ -374,6 +375,20 @@ func (mr *MockFullNodeMockRecorder) ChainNotify(arg0 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainNotify", reflect.TypeOf((*MockFullNode)(nil).ChainNotify), arg0)
}
// ChainPutObj mocks base method.
func (m *MockFullNode) ChainPutObj(arg0 context.Context, arg1 blocks.Block) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ChainPutObj", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// ChainPutObj indicates an expected call of ChainPutObj.
func (mr *MockFullNodeMockRecorder) ChainPutObj(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainPutObj", reflect.TypeOf((*MockFullNode)(nil).ChainPutObj), arg0, arg1)
}
// ChainReadObj mocks base method.
func (m *MockFullNode) ChainReadObj(arg0 context.Context, arg1 cid.Cid) ([]byte, error) {
m.ctrl.T.Helper()

View File

@ -34,6 +34,7 @@ import (
"github.com/filecoin-project/lotus/node/repo/imports"
"github.com/filecoin-project/specs-storage/storage"
"github.com/google/uuid"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
metrics "github.com/libp2p/go-libp2p-core/metrics"
"github.com/libp2p/go-libp2p-core/network"
@ -48,6 +49,8 @@ type ChainIOStruct struct {
Internal struct {
ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) ``
ChainPutObj func(p0 context.Context, p1 blocks.Block) error ``
ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) ``
}
}
@ -141,6 +144,8 @@ type FullNodeStruct struct {
ChainNotify func(p0 context.Context) (<-chan []*HeadChange, error) `perm:"read"`
ChainPutObj func(p0 context.Context, p1 blocks.Block) error `perm:"admin"`
ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `perm:"read"`
ChainSetHead func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"`
@ -511,6 +516,8 @@ type GatewayStruct struct {
ChainNotify func(p0 context.Context) (<-chan []*HeadChange, error) ``
ChainPutObj func(p0 context.Context, p1 blocks.Block) error ``
ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) ``
GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) ``
@ -977,6 +984,17 @@ func (s *ChainIOStub) ChainHasObj(p0 context.Context, p1 cid.Cid) (bool, error)
return false, ErrNotSupported
}
func (s *ChainIOStruct) ChainPutObj(p0 context.Context, p1 blocks.Block) error {
if s.Internal.ChainPutObj == nil {
return ErrNotSupported
}
return s.Internal.ChainPutObj(p0, p1)
}
func (s *ChainIOStub) ChainPutObj(p0 context.Context, p1 blocks.Block) error {
return ErrNotSupported
}
func (s *ChainIOStruct) ChainReadObj(p0 context.Context, p1 cid.Cid) ([]byte, error) {
if s.Internal.ChainReadObj == nil {
return *new([]byte), ErrNotSupported
@ -1307,6 +1325,17 @@ func (s *FullNodeStub) ChainNotify(p0 context.Context) (<-chan []*HeadChange, er
return nil, ErrNotSupported
}
func (s *FullNodeStruct) ChainPutObj(p0 context.Context, p1 blocks.Block) error {
if s.Internal.ChainPutObj == nil {
return ErrNotSupported
}
return s.Internal.ChainPutObj(p0, p1)
}
func (s *FullNodeStub) ChainPutObj(p0 context.Context, p1 blocks.Block) error {
return ErrNotSupported
}
func (s *FullNodeStruct) ChainReadObj(p0 context.Context, p1 cid.Cid) ([]byte, error) {
if s.Internal.ChainReadObj == nil {
return *new([]byte), ErrNotSupported
@ -3287,6 +3316,17 @@ func (s *GatewayStub) ChainNotify(p0 context.Context) (<-chan []*HeadChange, err
return nil, ErrNotSupported
}
func (s *GatewayStruct) ChainPutObj(p0 context.Context, p1 blocks.Block) error {
if s.Internal.ChainPutObj == nil {
return ErrNotSupported
}
return s.Internal.ChainPutObj(p0, p1)
}
func (s *GatewayStub) ChainPutObj(p0 context.Context, p1 blocks.Block) error {
return ErrNotSupported
}
func (s *GatewayStruct) ChainReadObj(p0 context.Context, p1 cid.Cid) ([]byte, error) {
if s.Internal.ChainReadObj == nil {
return *new([]byte), ErrNotSupported

View File

@ -11,6 +11,7 @@ import (
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-state-types/dline"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
textselector "github.com/ipld/go-ipld-selector-text-lite"
"github.com/libp2p/go-libp2p-core/peer"
@ -110,6 +111,9 @@ type FullNode interface {
// ChainDeleteObj deletes node referenced by the given CID
ChainDeleteObj(context.Context, cid.Cid) error //perm:admin
// ChainPutObj puts and object into the blockstore
ChainPutObj(context.Context, blocks.Block) error
// ChainHasObj checks if a given CID exists in the chain blockstore.
ChainHasObj(context.Context, cid.Cid) (bool, error) //perm:read

View File

@ -3,6 +3,7 @@ package v0api
import (
"context"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-address"
@ -34,6 +35,7 @@ import (
type Gateway interface {
ChainHasObj(context.Context, cid.Cid) (bool, error)
ChainPutObj(context.Context, blocks.Block) error
ChainHead(ctx context.Context) (*types.TipSet, error)
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error)

View File

@ -23,6 +23,7 @@ import (
marketevents "github.com/filecoin-project/lotus/markets/loggers"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/node/repo/imports"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p-core/peer"
"golang.org/x/xerrors"
@ -74,6 +75,8 @@ type FullNodeStruct struct {
ChainNotify func(p0 context.Context) (<-chan []*api.HeadChange, error) `perm:"read"`
ChainPutObj func(p0 context.Context, p1 blocks.Block) error ``
ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) `perm:"read"`
ChainSetHead func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"`
@ -420,6 +423,8 @@ type GatewayStruct struct {
ChainNotify func(p0 context.Context) (<-chan []*api.HeadChange, error) ``
ChainPutObj func(p0 context.Context, p1 blocks.Block) error ``
ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) ``
GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *api.MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) ``
@ -682,6 +687,17 @@ func (s *FullNodeStub) ChainNotify(p0 context.Context) (<-chan []*api.HeadChange
return nil, ErrNotSupported
}
func (s *FullNodeStruct) ChainPutObj(p0 context.Context, p1 blocks.Block) error {
if s.Internal.ChainPutObj == nil {
return ErrNotSupported
}
return s.Internal.ChainPutObj(p0, p1)
}
func (s *FullNodeStub) ChainPutObj(p0 context.Context, p1 blocks.Block) error {
return ErrNotSupported
}
func (s *FullNodeStruct) ChainReadObj(p0 context.Context, p1 cid.Cid) ([]byte, error) {
if s.Internal.ChainReadObj == nil {
return *new([]byte), ErrNotSupported
@ -2530,6 +2546,17 @@ func (s *GatewayStub) ChainNotify(p0 context.Context) (<-chan []*api.HeadChange,
return nil, ErrNotSupported
}
func (s *GatewayStruct) ChainPutObj(p0 context.Context, p1 blocks.Block) error {
if s.Internal.ChainPutObj == nil {
return ErrNotSupported
}
return s.Internal.ChainPutObj(p0, p1)
}
func (s *GatewayStub) ChainPutObj(p0 context.Context, p1 blocks.Block) error {
return ErrNotSupported
}
func (s *GatewayStruct) ChainReadObj(p0 context.Context, p1 cid.Cid) ([]byte, error) {
if s.Internal.ChainReadObj == nil {
return *new([]byte), ErrNotSupported

View File

@ -33,6 +33,7 @@ import (
imports "github.com/filecoin-project/lotus/node/repo/imports"
gomock "github.com/golang/mock/gomock"
uuid "github.com/google/uuid"
blocks "github.com/ipfs/go-block-format"
cid "github.com/ipfs/go-cid"
metrics "github.com/libp2p/go-libp2p-core/metrics"
network0 "github.com/libp2p/go-libp2p-core/network"
@ -377,6 +378,20 @@ func (mr *MockFullNodeMockRecorder) ChainNotify(arg0 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainNotify", reflect.TypeOf((*MockFullNode)(nil).ChainNotify), arg0)
}
// ChainPutObj mocks base method.
func (m *MockFullNode) ChainPutObj(arg0 context.Context, arg1 blocks.Block) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ChainPutObj", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// ChainPutObj indicates an expected call of ChainPutObj.
func (mr *MockFullNodeMockRecorder) ChainPutObj(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainPutObj", reflect.TypeOf((*MockFullNode)(nil).ChainPutObj), arg0, arg1)
}
// ChainReadObj mocks base method.
func (m *MockFullNode) ChainReadObj(arg0 context.Context, arg1 cid.Cid) ([]byte, error) {
m.ctrl.T.Helper()

View File

@ -11,6 +11,7 @@ import (
type ChainIO interface {
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainHasObj(context.Context, cid.Cid) (bool, error)
ChainPutObj(context.Context, blocks.Block) error
}
type apiBlockstore struct {
@ -49,12 +50,18 @@ func (a *apiBlockstore) GetSize(ctx context.Context, c cid.Cid) (int, error) {
return len(bb), nil
}
func (a *apiBlockstore) Put(context.Context, blocks.Block) error {
return xerrors.New("not supported")
func (a *apiBlockstore) Put(ctx context.Context, block blocks.Block) error {
return a.api.ChainPutObj(ctx, block)
}
func (a *apiBlockstore) PutMany(context.Context, []blocks.Block) error {
return xerrors.New("not supported")
func (a *apiBlockstore) PutMany(ctx context.Context, blocks []blocks.Block) error {
for _, block := range blocks {
err := a.api.ChainPutObj(ctx, block)
if err != nil {
return err
}
}
return nil
}
func (a *apiBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -4,6 +4,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
"golang.org/x/xerrors"
@ -48,11 +49,11 @@ func Load(store adt.Store, act *types.Actor) (State, error) {
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
}
func MakeState(store adt.Store, av actors.Version) (State, error) {
func MakeState(store adt.Store, av actors.Version, builtinActors cid.Cid) (State, error) {
switch av {
{{range .versions}}
case actors.Version{{.}}:
return make{{.}}(store)
return make{{.}}(store{{if (ge . 8)}}, builtinActors{{end}})
{{end}}
}
return nil, xerrors.Errorf("unknown actor version %d", av)
@ -60,4 +61,5 @@ func MakeState(store adt.Store, av actors.Version) (State, error) {
type State interface {
GetState() interface{}
GetBuiltinActors() cid.Cid
}

View File

@ -23,9 +23,11 @@ func load{{.v}}(store adt.Store, root cid.Cid) (State, error) {
return &out, nil
}
func make{{.v}}(store adt.Store) (State, error) {
func make{{.v}}(store adt.Store{{if (ge .v 8)}}, builtinActors cid.Cid{{end}}) (State, error) {
out := state{{.v}}{store: store}
out.State = system{{.v}}.State{}
out.State = system{{.v}}.State{
{{if (ge .v 8)}}BuiltinActors: builtinActors,{{end}}
}
return &out, nil
}
@ -36,4 +38,12 @@ type state{{.v}} struct {
func (s *state{{.v}}) GetState() interface{} {
return &s.State
}
func (s *state{{.v}}) GetBuiltinActors() cid.Cid {
{{if (le .v 7)}}
return cid.Undef
{{else}}
return s.State.BuiltinActors
{{end}}
}

View File

@ -4,6 +4,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
"golang.org/x/xerrors"
@ -70,7 +71,7 @@ func Load(store adt.Store, act *types.Actor) (State, error) {
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
}
func MakeState(store adt.Store, av actors.Version) (State, error) {
func MakeState(store adt.Store, av actors.Version, builtinActors cid.Cid) (State, error) {
switch av {
case actors.Version0:
@ -95,7 +96,7 @@ func MakeState(store adt.Store, av actors.Version) (State, error) {
return make7(store)
case actors.Version8:
return make8(store)
return make8(store, builtinActors)
}
return nil, xerrors.Errorf("unknown actor version %d", av)
@ -103,4 +104,5 @@ func MakeState(store adt.Store, av actors.Version) (State, error) {
type State interface {
GetState() interface{}
GetBuiltinActors() cid.Cid
}

View File

@ -33,3 +33,9 @@ type state0 struct {
func (s *state0) GetState() interface{} {
return &s.State
}
func (s *state0) GetBuiltinActors() cid.Cid {
return cid.Undef
}

View File

@ -33,3 +33,9 @@ type state2 struct {
func (s *state2) GetState() interface{} {
return &s.State
}
func (s *state2) GetBuiltinActors() cid.Cid {
return cid.Undef
}

View File

@ -33,3 +33,9 @@ type state3 struct {
func (s *state3) GetState() interface{} {
return &s.State
}
func (s *state3) GetBuiltinActors() cid.Cid {
return cid.Undef
}

View File

@ -33,3 +33,9 @@ type state4 struct {
func (s *state4) GetState() interface{} {
return &s.State
}
func (s *state4) GetBuiltinActors() cid.Cid {
return cid.Undef
}

View File

@ -33,3 +33,9 @@ type state5 struct {
func (s *state5) GetState() interface{} {
return &s.State
}
func (s *state5) GetBuiltinActors() cid.Cid {
return cid.Undef
}

View File

@ -33,3 +33,9 @@ type state6 struct {
func (s *state6) GetState() interface{} {
return &s.State
}
func (s *state6) GetBuiltinActors() cid.Cid {
return cid.Undef
}

View File

@ -33,3 +33,9 @@ type state7 struct {
func (s *state7) GetState() interface{} {
return &s.State
}
func (s *state7) GetBuiltinActors() cid.Cid {
return cid.Undef
}

View File

@ -19,9 +19,11 @@ func load8(store adt.Store, root cid.Cid) (State, error) {
return &out, nil
}
func make8(store adt.Store) (State, error) {
func make8(store adt.Store, builtinActors cid.Cid) (State, error) {
out := state8{store: store}
out.State = system8.State{}
out.State = system8.State{
BuiltinActors: builtinActors,
}
return &out, nil
}
@ -33,3 +35,9 @@ type state8 struct {
func (s *state8) GetState() interface{} {
return &s.State
}
func (s *state8) GetBuiltinActors() cid.Cid {
return s.State.BuiltinActors
}

View File

@ -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,8 +13,10 @@ 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"
gstStore "github.com/filecoin-project/go-state-types/store"
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
@ -33,12 +29,16 @@ 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"
"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 +1431,155 @@ func upgradeActorsV8Common(
return newRoot, nil
}
// Example upgrade function if upgrade requires only code changes
//func UpgradeActorsV9(ctx context.Context, sm *stmgr.StateManager, _ stmgr.MigrationCache, _ stmgr.ExecMonitor, root cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) (cid.Cid, error) {
// buf := blockstore.NewTieredBstore(sm.ChainStore().StateBlockstore(), blockstore.NewMemorySync())
//
// av := actors.Version9
// // This may change for upgrade
// newStateTreeVersion := types.StateTreeVersion4
//
// // ensure that the manifest is loaded in the blockstore
// if err := bundle.FetchAndLoadBundles(ctx, buf, map[actors.Version]build.Bundle{
// av: build.BuiltinActorReleases[av],
// }); err != nil {
// return cid.Undef, xerrors.Errorf("failed to load manifest bundle: %w", err)
// }
//
// newActorsManifestCid, ok := actors.GetManifest(av)
// if !ok {
// return cid.Undef, xerrors.Errorf("no manifest CID for v8 upgrade")
// }
//
// bstore := sm.ChainStore().StateBlockstore()
// return LiteMigration(ctx, bstore, newActorsManifestCid, root, av, types.StateTreeVersion4, newStateTreeVersion)
//}
func LiteMigration(ctx context.Context, bstore blockstore.Blockstore, newActorsManifestCid cid.Cid, root cid.Cid, av actors.Version, oldStateTreeVersion types.StateTreeVersion, newStateTreeVersion types.StateTreeVersion) (cid.Cid, error) {
buf := blockstore.NewTieredBstore(bstore, blockstore.NewMemorySync())
store := store.ActorStore(ctx, buf)
adtStore := gstStore.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 != oldStateTreeVersion {
return cid.Undef, xerrors.Errorf(
"expected state tree version %d for actors code upgrade, got %d",
oldStateTreeVersion,
stateRoot.Version,
)
}
st, err := state.LoadStateTree(store, root)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to load state tree: %w", err)
}
oldManifest, err := stmgr.GetManifest(ctx, st)
if err != nil {
return cid.Undef, xerrors.Errorf("error loading old actor manifest: %w", err)
}
oldManifestData := manifest.ManifestData{}
if err := store.Get(ctx, oldManifest.Data, &oldManifestData); err != nil {
return cid.Undef, xerrors.Errorf("error loading old manifest data: %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)
}
if len(oldManifestData.Entries) != len(actors.GetBuiltinActorsKeys()) {
return cid.Undef, xerrors.Errorf("incomplete old manifest with %d code CIDs", len(oldManifestData.Entries))
}
if len(newManifestData.Entries) != len(actors.GetBuiltinActorsKeys()) {
return cid.Undef, xerrors.Errorf("incomplete new manifest with %d code CIDs", len(newManifestData.Entries))
}
// 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 old manifest", entry.Name)
}
migrations[oldCodeCid] = entry.Code
}
startTime := time.Now()
// Load output state tree
actorsOut, err := state.NewStateTree(adtStore, newStateTreeVersion)
if err != nil {
return cid.Undef, err
}
// Insert migrated records in output state tree.
err = st.ForEach(func(addr address.Address, actorIn *types.Actor) error {
newCid, ok := migrations[actorIn.Code]
if !ok {
return xerrors.Errorf("new code cid not found in migrations for actor %s", addr)
}
var head cid.Cid
if addr == system.Address {
newSystemState, err := system.MakeState(store, av, newManifest.Data)
if err != nil {
return xerrors.Errorf("could not make system actor state: %w", err)
}
head, err = store.Put(ctx, newSystemState)
if err != nil {
return xerrors.Errorf("could not set system actor state head: %w", err)
}
} else {
head = actorIn.Head
}
newActor := types.Actor{
Code: newCid,
Head: head,
Nonce: actorIn.Nonce,
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
})
if err != nil {
return cid.Undef, xerrors.Errorf("failed update actor states: %w", err)
}
elapsed := time.Since(startTime)
log.Infof("All done after %v. Flushing state tree root.", elapsed)
newRoot, err := actorsOut.Flush(ctx)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to flush new actors: %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{}) {

View File

@ -4,6 +4,8 @@ import (
"context"
"sync"
blocks "github.com/ipfs/go-block-format"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/types"
@ -39,6 +41,10 @@ func (m *MockAPI) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) {
return blk.RawData(), nil
}
func (m *MockAPI) ChainPutObj(ctx context.Context, block blocks.Block) error {
return m.bs.Put(ctx, block)
}
func (m *MockAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
m.lk.Lock()
defer m.lk.Unlock()

View File

@ -3,6 +3,8 @@ package genesis
import (
"context"
"github.com/ipfs/go-cid"
systemtypes "github.com/filecoin-project/go-state-types/builtin/v8/system"
"github.com/filecoin-project/go-state-types/manifest"
@ -25,7 +27,8 @@ import (
func SetupSystemActor(ctx context.Context, bs bstore.Blockstore, av actors.Version) (*types.Actor, error) {
cst := cbor.NewCborStore(bs)
st, err := system.MakeState(adt.WrapStore(ctx, cst), av)
// TODO pass in built-in actors cid for V8 and later
st, err := system.MakeState(adt.WrapStore(ctx, cst), av, cid.Undef)
if err != nil {
return nil, err
}

View File

@ -5,7 +5,7 @@ import (
"context"
"os"
"github.com/filecoin-project/lotus/chain/rand"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-bitfield"
@ -15,8 +15,6 @@ import (
"github.com/filecoin-project/go-state-types/network"
cid "github.com/ipfs/go-cid"
"golang.org/x/xerrors"
miner_types "github.com/filecoin-project/go-state-types/builtin/v8/miner"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors/builtin"
@ -25,6 +23,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
"github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/rand"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"

View File

@ -5,18 +5,21 @@ import (
"fmt"
"reflect"
"github.com/filecoin-project/lotus/chain/rand"
"github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-state-types/manifest"
gstStore "github.com/filecoin-project/go-state-types/store"
"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/lotus/api"
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
"github.com/filecoin-project/lotus/chain/actors/builtin/system"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/rand"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
@ -211,3 +214,42 @@ func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([]
return out, nil
}
func GetManifest(ctx context.Context, st *state.StateTree) (*manifest.Manifest, error) {
wrapStore := gstStore.WrapStore(ctx, st.Store)
systemActor, err := st.GetActor(system.Address)
if err != nil {
return nil, fmt.Errorf("failed to get system actor: %w", err)
}
systemActorState, err := system.Load(wrapStore, systemActor)
if err != nil {
return nil, xerrors.Errorf("failed to load system actor state: %w", err)
}
actorsManifestCid := systemActorState.GetBuiltinActors()
mf := manifest.Manifest{
Version: 1,
Data: actorsManifestCid,
}
if err := mf.Load(ctx, wrapStore); err != nil {
return nil, xerrors.Errorf("failed to load actor manifest: %w", err)
}
manifestData := manifest.ManifestData{}
if err := st.Store.Get(ctx, mf.Data, &manifestData); err != nil {
return nil, xerrors.Errorf("failed to load manifest data: %w", err)
}
return &mf, nil
}
func GetManifestEntries(ctx context.Context, st *state.StateTree) ([]manifest.ManifestEntry, error) {
mf, err := GetManifest(ctx, st)
if err != nil {
return nil, xerrors.Errorf("failed to get manifest: %w", err)
}
manifestData := manifest.ManifestData{}
if err := st.Store.Get(ctx, mf.Data, &manifestData); err != nil {
return nil, xerrors.Errorf("filed to load manifest data: %w", err)
}
return manifestData.Entries, nil
}

View File

@ -29,6 +29,7 @@
* [ChainHasObj](#ChainHasObj)
* [ChainHead](#ChainHead)
* [ChainNotify](#ChainNotify)
* [ChainPutObj](#ChainPutObj)
* [ChainReadObj](#ChainReadObj)
* [ChainSetHead](#ChainSetHead)
* [ChainStatObj](#ChainStatObj)
@ -971,6 +972,21 @@ Response:
]
```
### ChainPutObj
ChainPutObj puts and object into the blockstore
Perms:
Inputs:
```json
[
{}
]
```
Response: `{}`
### ChainReadObj
ChainReadObj reads ipld nodes referenced by the specified CID from chain
blockstore and returns raw bytes.

View File

@ -28,6 +28,7 @@
* [ChainHasObj](#ChainHasObj)
* [ChainHead](#ChainHead)
* [ChainNotify](#ChainNotify)
* [ChainPutObj](#ChainPutObj)
* [ChainReadObj](#ChainReadObj)
* [ChainSetHead](#ChainSetHead)
* [ChainStatObj](#ChainStatObj)
@ -959,6 +960,21 @@ Response:
]
```
### ChainPutObj
ChainPutObj puts a given object into the block store
Perms: admin
Inputs:
```json
[
{}
]
```
Response: `{}`
### ChainReadObj
ChainReadObj reads ipld nodes referenced by the specified CID from chain
blockstore and returns raw bytes.

View File

@ -5,6 +5,7 @@ import (
"fmt"
"time"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
"golang.org/x/xerrors"
@ -46,6 +47,7 @@ type TargetAPI interface {
ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
ChainGetPath(ctx context.Context, from, to types.TipSetKey) ([]*api.HeadChange, error)
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainPutObj(context.Context, blocks.Block) error
ChainGetGenesis(context.Context) (*types.TipSet, error)
GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
MpoolPushUntrusted(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
@ -251,6 +253,10 @@ func (gw *Node) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) {
return gw.target.ChainReadObj(ctx, c)
}
func (gw *Node) ChainPutObj(context.Context, blocks.Block) error {
return xerrors.New("not supported")
}
func (gw *Node) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
if err := gw.checkTipsetKey(ctx, tsk); err != nil {
return nil, err

4
go.mod
View File

@ -41,7 +41,7 @@ require (
github.com/filecoin-project/go-legs v0.3.10
github.com/filecoin-project/go-padreader v0.0.1
github.com/filecoin-project/go-paramfetch v0.0.4
github.com/filecoin-project/go-state-types v0.1.7
github.com/filecoin-project/go-state-types v0.1.9
github.com/filecoin-project/go-statemachine v1.0.2
github.com/filecoin-project/go-statestore v0.2.0
github.com/filecoin-project/go-storedcounter v0.1.0
@ -54,7 +54,7 @@ require (
github.com/filecoin-project/specs-actors/v5 v5.0.6-0.20220514165557-0b29a778685b
github.com/filecoin-project/specs-actors/v6 v6.0.2-0.20220511204807-569c6d12432b
github.com/filecoin-project/specs-actors/v7 v7.0.1-0.20220511223846-637436c27154
github.com/filecoin-project/specs-actors/v8 v8.0.0-20220422153930-0afe155bfffa
github.com/filecoin-project/specs-actors/v8 v8.0.1
github.com/filecoin-project/specs-storage v0.4.1
github.com/filecoin-project/test-vectors/schema v0.0.5
github.com/gbrlsnchs/jwt/v3 v3.0.1

8
go.sum
View File

@ -372,8 +372,8 @@ github.com/filecoin-project/go-state-types v0.1.3/go.mod h1:ezYnPf0bNkTsDibL/psS
github.com/filecoin-project/go-state-types v0.1.4-0.20220511200558-7a486892661a/go.mod h1:xCA/WfKlC2zcn3fUmDv4IrzznwS98X5XW/irUP3Lhxg=
github.com/filecoin-project/go-state-types v0.1.4/go.mod h1:xCA/WfKlC2zcn3fUmDv4IrzznwS98X5XW/irUP3Lhxg=
github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
github.com/filecoin-project/go-state-types v0.1.7 h1:r/ZzyUA+CqY8IXyHsLtliqRgPFaON+aC2MmWKm1nl98=
github.com/filecoin-project/go-state-types v0.1.7/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
github.com/filecoin-project/go-state-types v0.1.9 h1:7ffQu+arDAiW5dphWTl8WdgWTo9Kt3BsjGcNYr99crI=
github.com/filecoin-project/go-state-types v0.1.9/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=
github.com/filecoin-project/go-statemachine v1.0.2-0.20220322104818-27f8fbb86dfd/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54=
github.com/filecoin-project/go-statemachine v1.0.2 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc=
@ -410,8 +410,8 @@ github.com/filecoin-project/specs-actors/v6 v6.0.2-0.20220511204807-569c6d12432b
github.com/filecoin-project/specs-actors/v7 v7.0.0/go.mod h1:TA5FwCna+Yi36POaT7SLKXsgEDvJwc0V/L6ZsO19B9M=
github.com/filecoin-project/specs-actors/v7 v7.0.1-0.20220511223846-637436c27154 h1:NKA2mpz3GAksmrP7P13zLufvoYG9DlasgKxdhrk9gGM=
github.com/filecoin-project/specs-actors/v7 v7.0.1-0.20220511223846-637436c27154/go.mod h1:2pWr2Soyl4yfOkoMThzj41l2lPIRC+CUgU5cW3wI+K4=
github.com/filecoin-project/specs-actors/v8 v8.0.0-20220422153930-0afe155bfffa h1:P9l2WQMvWUJ450esBttbAaqH8Lhe1hu1W2J6cQsiZcA=
github.com/filecoin-project/specs-actors/v8 v8.0.0-20220422153930-0afe155bfffa/go.mod h1:UYIPg65iPWoFw5NEftREdJwv9b/5yaLKdCgTvNI/2FA=
github.com/filecoin-project/specs-actors/v8 v8.0.1 h1:4u0tIRJeT5G7F05lwLRIsDnsrN+bJ5Ixj6h49Q7uE2Y=
github.com/filecoin-project/specs-actors/v8 v8.0.1/go.mod h1:UYIPg65iPWoFw5NEftREdJwv9b/5yaLKdCgTvNI/2FA=
github.com/filecoin-project/specs-storage v0.4.1 h1:yvLEaLZj8f+uByhNC4mFOtCUyL2wQku+NGBp6hjTe9M=
github.com/filecoin-project/specs-storage v0.4.1/go.mod h1:Z2eK6uMwAOSLjek6+sy0jNV2DSsMEENziMUz0GHRFBw=
github.com/filecoin-project/storetheindex v0.3.5 h1:KoS9TvjPm6zIZfUH8atAHJbVHOO7GTP1MdTG+v0eE+Q=

View File

@ -0,0 +1,120 @@
package itests
import (
"context"
"fmt"
"testing"
"time"
"github.com/ipfs/go-cid"
mh "github.com/multiformats/go-multihash"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/manifest"
"github.com/filecoin-project/go-state-types/network"
gstStore "github.com/filecoin-project/go-state-types/store"
"github.com/filecoin-project/specs-actors/v8/actors/util/adt"
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
"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 := gstStore.WrapBlockStore(ctx, bs)
ts, err := client16.ChainHead(ctx)
require.NoError(t, err)
stateRoot := ts.ParentState()
oldStateTree, err := state.LoadStateTree(ctxStore, stateRoot)
require.NoError(t, err)
oldManifest, err := stmgr.GetManifest(ctx, oldStateTree)
require.NoError(t, err)
newManifestCid := makeTestManifest(t, ctxStore)
// Use the Cid we generated to get the new manifest instead of loading it from the state tree, because that would not test that we have the correct manifest in the state
var newManifest manifest.Manifest
err = ctxStore.Get(ctx, newManifestCid, &newManifest)
require.NoError(t, err)
err = newManifest.Load(ctx, ctxStore)
require.NoError(t, err)
newManifestData := manifest.ManifestData{}
err = ctxStore.Get(ctx, newManifest.Data, &newManifestData)
require.NoError(t, err)
newStateRoot, err := filcns.LiteMigration(ctx, bs, newManifestCid, stateRoot, actors.Version8, types.StateTreeVersion4, types.StateTreeVersion4)
require.NoError(t, err)
newStateTree, err := state.LoadStateTree(ctxStore, newStateRoot)
require.NoError(t, err)
migrations := make(map[cid.Cid]cid.Cid)
for _, entry := range newManifestData.Entries {
oldCodeCid, ok := oldManifest.Get(entry.Name)
require.True(t, ok)
migrations[oldCodeCid] = entry.Code
}
err = newStateTree.ForEach(func(addr address.Address, newActorState *types.Actor) error {
oldActor, err := oldStateTree.GetActor(addr)
require.NoError(t, err)
newCodeCid, ok := migrations[oldActor.Code]
require.True(t, ok)
require.Equal(t, newCodeCid, newActorState.Code)
return nil
})
require.NoError(t, err)
}
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
}

View File

@ -3,6 +3,7 @@ package storageadapter
import (
"context"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
"golang.org/x/xerrors"
@ -20,6 +21,7 @@ type apiWrapper struct {
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainHasObj(context.Context, cid.Cid) (bool, error)
ChainPutObj(context.Context, blocks.Block) error
}
}

View File

@ -15,6 +15,7 @@ import (
"go.uber.org/fx"
"golang.org/x/xerrors"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-blockservice"
"github.com/ipfs/go-cid"
offline "github.com/ipfs/go-ipfs-exchange-offline"
@ -261,6 +262,10 @@ func (m *ChainModule) ChainReadObj(ctx context.Context, obj cid.Cid) ([]byte, er
return blk.RawData(), nil
}
func (a *ChainAPI) ChainPutObj(ctx context.Context, obj blocks.Block) error {
return a.ExposedBlockstore.Put(ctx, obj)
}
func (a *ChainAPI) ChainDeleteObj(ctx context.Context, obj cid.Cid) error {
return a.ExposedBlockstore.DeleteBlock(ctx, obj)
}

View File

@ -6,6 +6,7 @@ import (
"time"
"github.com/filecoin-project/go-bitfield"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
logging "github.com/ipfs/go-log/v2"
@ -122,6 +123,7 @@ type fullNodeFilteredAPI interface {
ChainGetPath(ctx context.Context, from, to types.TipSetKey) ([]*api.HeadChange, error)
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainHasObj(context.Context, cid.Cid) (bool, error)
ChainPutObj(context.Context, blocks.Block) error
ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error)
WalletSign(context.Context, address.Address, []byte) (*crypto.Signature, error)