diff --git a/.circleci/config.yml b/.circleci/config.yml index e99c88099e7..c2ce75f9c98 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 diff --git a/api/api_full.go b/api/api_full.go index 7abe419aaf0..8c3c64ce2b8 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -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. diff --git a/api/api_gateway.go b/api/api_gateway.go index 6e92c6e0de0..ab5f497fe5a 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -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) diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index cebf15d6699..d7840fd8abf 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -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) diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 689a67834f9..9a2bda0b4ac 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -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() diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 0cbb04751df..0177ef27783 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -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) `` Discover func(p0 context.Context) (apitypes.OpenRPCDocument, error) `` @@ -981,6 +988,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 @@ -1311,6 +1329,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 @@ -3291,6 +3320,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 diff --git a/api/v0api/full.go b/api/v0api/full.go index 30a0dfb8e0a..4721f4c633e 100644 --- a/api/v0api/full.go +++ b/api/v0api/full.go @@ -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 diff --git a/api/v0api/gateway.go b/api/v0api/gateway.go index e13e92dd386..70994c7400a 100644 --- a/api/v0api/gateway.go +++ b/api/v0api/gateway.go @@ -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) diff --git a/api/v0api/proxy_gen.go b/api/v0api/proxy_gen.go index bae8ba7824d..a2a69f16309 100644 --- a/api/v0api/proxy_gen.go +++ b/api/v0api/proxy_gen.go @@ -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 diff --git a/api/v0api/v0mocks/mock_full.go b/api/v0api/v0mocks/mock_full.go index e807862e625..ef194e9d353 100644 --- a/api/v0api/v0mocks/mock_full.go +++ b/api/v0api/v0mocks/mock_full.go @@ -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() diff --git a/blockstore/api.go b/blockstore/api.go index dc4c034525d..090f53e5a99 100644 --- a/blockstore/api.go +++ b/blockstore/api.go @@ -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) { diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 01c02e14fb4..5f73b3a45e8 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index 12a5ebaca11..5a9eb751152 100644 Binary files a/build/openrpc/gateway.json.gz and b/build/openrpc/gateway.json.gz differ diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index b10e9b76136..93112005667 100644 Binary files a/build/openrpc/miner.json.gz and b/build/openrpc/miner.json.gz differ diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index 155ac591e43..4e7e7b530e6 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/chain/actors/builtin/system/actor.go.template b/chain/actors/builtin/system/actor.go.template index 616a20a76d1..c5e1af3e42c 100644 --- a/chain/actors/builtin/system/actor.go.template +++ b/chain/actors/builtin/system/actor.go.template @@ -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 } diff --git a/chain/actors/builtin/system/state.go.template b/chain/actors/builtin/system/state.go.template index ddf458305e9..21b057ad5d1 100644 --- a/chain/actors/builtin/system/state.go.template +++ b/chain/actors/builtin/system/state.go.template @@ -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}} } \ No newline at end of file diff --git a/chain/actors/builtin/system/system.go b/chain/actors/builtin/system/system.go index 71d7f7024c0..64a0f3cbaea 100644 --- a/chain/actors/builtin/system/system.go +++ b/chain/actors/builtin/system/system.go @@ -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 } diff --git a/chain/actors/builtin/system/v0.go b/chain/actors/builtin/system/v0.go index 64c6f53d3cf..a5aa8e8fa1b 100644 --- a/chain/actors/builtin/system/v0.go +++ b/chain/actors/builtin/system/v0.go @@ -33,3 +33,9 @@ type state0 struct { func (s *state0) GetState() interface{} { return &s.State } + +func (s *state0) GetBuiltinActors() cid.Cid { + + return cid.Undef + +} diff --git a/chain/actors/builtin/system/v2.go b/chain/actors/builtin/system/v2.go index eb540891cc3..aea9eff7b91 100644 --- a/chain/actors/builtin/system/v2.go +++ b/chain/actors/builtin/system/v2.go @@ -33,3 +33,9 @@ type state2 struct { func (s *state2) GetState() interface{} { return &s.State } + +func (s *state2) GetBuiltinActors() cid.Cid { + + return cid.Undef + +} diff --git a/chain/actors/builtin/system/v3.go b/chain/actors/builtin/system/v3.go index 5b04e189ee6..fd5f0cd5051 100644 --- a/chain/actors/builtin/system/v3.go +++ b/chain/actors/builtin/system/v3.go @@ -33,3 +33,9 @@ type state3 struct { func (s *state3) GetState() interface{} { return &s.State } + +func (s *state3) GetBuiltinActors() cid.Cid { + + return cid.Undef + +} diff --git a/chain/actors/builtin/system/v4.go b/chain/actors/builtin/system/v4.go index b6c92497884..fbdec7e93bf 100644 --- a/chain/actors/builtin/system/v4.go +++ b/chain/actors/builtin/system/v4.go @@ -33,3 +33,9 @@ type state4 struct { func (s *state4) GetState() interface{} { return &s.State } + +func (s *state4) GetBuiltinActors() cid.Cid { + + return cid.Undef + +} diff --git a/chain/actors/builtin/system/v5.go b/chain/actors/builtin/system/v5.go index 77d2a8478be..3d3c27a12e4 100644 --- a/chain/actors/builtin/system/v5.go +++ b/chain/actors/builtin/system/v5.go @@ -33,3 +33,9 @@ type state5 struct { func (s *state5) GetState() interface{} { return &s.State } + +func (s *state5) GetBuiltinActors() cid.Cid { + + return cid.Undef + +} diff --git a/chain/actors/builtin/system/v6.go b/chain/actors/builtin/system/v6.go index 689620afba7..3143088456c 100644 --- a/chain/actors/builtin/system/v6.go +++ b/chain/actors/builtin/system/v6.go @@ -33,3 +33,9 @@ type state6 struct { func (s *state6) GetState() interface{} { return &s.State } + +func (s *state6) GetBuiltinActors() cid.Cid { + + return cid.Undef + +} diff --git a/chain/actors/builtin/system/v7.go b/chain/actors/builtin/system/v7.go index 813add5fb14..3987db8dd40 100644 --- a/chain/actors/builtin/system/v7.go +++ b/chain/actors/builtin/system/v7.go @@ -33,3 +33,9 @@ type state7 struct { func (s *state7) GetState() interface{} { return &s.State } + +func (s *state7) GetBuiltinActors() cid.Cid { + + return cid.Undef + +} diff --git a/chain/actors/builtin/system/v8.go b/chain/actors/builtin/system/v8.go index 2e0e2ba56da..a30d5fa305f 100644 --- a/chain/actors/builtin/system/v8.go +++ b/chain/actors/builtin/system/v8.go @@ -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 + +} diff --git a/chain/consensus/filcns/upgrades.go b/chain/consensus/filcns/upgrades.go index d2a18291744..1e9f17d71c8 100644 --- a/chain/consensus/filcns/upgrades.go +++ b/chain/consensus/filcns/upgrades.go @@ -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{}) { diff --git a/chain/events/state/mock/api.go b/chain/events/state/mock/api.go index 7a73355a523..a66b65b3e12 100644 --- a/chain/events/state/mock/api.go +++ b/chain/events/state/mock/api.go @@ -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() diff --git a/chain/gen/genesis/f00_system.go b/chain/gen/genesis/f00_system.go index faa585c957d..527701f1718 100644 --- a/chain/gen/genesis/f00_system.go +++ b/chain/gen/genesis/f00_system.go @@ -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 } diff --git a/chain/stmgr/actors.go b/chain/stmgr/actors.go index d8d121f02bc..bfa04827ec1 100644 --- a/chain/stmgr/actors.go +++ b/chain/stmgr/actors.go @@ -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" diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 2a84c777b3a..61eb5fcb00a 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -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 +} diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index 87666bfd934..7060f9a811d 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -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. diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index 07f9b8684c9..325a48babb5 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -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. diff --git a/gateway/node.go b/gateway/node.go index bf54530f02b..1992c53b790 100644 --- a/gateway/node.go +++ b/gateway/node.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" "go.opencensus.io/stats" "golang.org/x/time/rate" @@ -55,6 +56,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) @@ -332,6 +334,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.limit(ctx, stateRateLimitTokens); err != nil { return nil, err diff --git a/go.mod b/go.mod index 28004eab07d..566575efcee 100644 --- a/go.mod +++ b/go.mod @@ -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 github.com/filecoin-project/specs-actors/v6 v6.0.2 github.com/filecoin-project/specs-actors/v7 v7.0.1 - github.com/filecoin-project/specs-actors/v8 v8.0.0 + 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 diff --git a/go.sum b/go.sum index c13f587f962..609ce7d268f 100644 --- a/go.sum +++ b/go.sum @@ -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/go.mod h1:xCA/WfKlC2zcn3fUmDv4IrzznwS98X5XW/irUP3Lhxg= github.com/filecoin-project/go-state-types v0.1.5/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= 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= @@ -411,8 +411,8 @@ github.com/filecoin-project/specs-actors/v6 v6.0.2/go.mod h1:wnfVvPnYmzPZilNvSqC 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 h1:w72xCxijK7xs1qzmJiw+WYJaVt2EPHN8oiwpA1Ay3/4= github.com/filecoin-project/specs-actors/v7 v7.0.1/go.mod h1:tPLEYXoXhcpyLh69Ccq91SOuLXsPWjHiY27CzawjUEk= -github.com/filecoin-project/specs-actors/v8 v8.0.0 h1:c6NztoE4J5j7KvIfGmx9XW9o5aszPl6DU0M4xDqAJVU= -github.com/filecoin-project/specs-actors/v8 v8.0.0/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= diff --git a/itests/lite_migration_test.go b/itests/lite_migration_test.go new file mode 100644 index 00000000000..8701dac4e45 --- /dev/null +++ b/itests/lite_migration_test.go @@ -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 +} diff --git a/markets/storageadapter/api.go b/markets/storageadapter/api.go index c49a96f885b..4316174bc96 100644 --- a/markets/storageadapter/api.go +++ b/markets/storageadapter/api.go @@ -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 } } diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 61be82bc9e6..97bf260a422 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -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) } diff --git a/storage/miner.go b/storage/miner.go index 5a97c5f6a0f..80f06581f43 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -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)