diff --git a/api/test/ccupgrade.go b/api/test/ccupgrade.go index f58f1ff6e..97fb665ed 100644 --- a/api/test/ccupgrade.go +++ b/api/test/ccupgrade.go @@ -12,15 +12,36 @@ import ( "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node" "github.com/filecoin-project/lotus/node/impl" ) func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) { _ = os.Setenv("BELLMAN_NO_GPU", "1") + for _, height := range []abi.ChainEpoch{ + 1, // before + 162, // while sealing + 520, // after upgrade deal + 5000, // after + } { + height := height // make linters happy by copying + t.Run(fmt.Sprintf("upgrade-%d", height), func(t *testing.T) { + testCCUpgrade(t, b, blocktime, height) + }) + } +} + +func testCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, upgradeHeight abi.ChainEpoch) { ctx := context.Background() - n, sn := b(t, 1, OneMiner) + n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{ + Network: build.ActorUpgradeNetworkVersion, + Height: upgradeHeight, + Migration: stmgr.UpgradeActorsV2, + }})) client := n[0].FullNode.(*impl.FullNodeAPI) miner := sn[0] diff --git a/api/test/deals.go b/api/test/deals.go index 12cd0607a..aa5bfa716 100644 --- a/api/test/deals.go +++ b/api/test/deals.go @@ -402,9 +402,12 @@ func testRetrieval(t *testing.T, ctx context.Context, client *impl.FullNodeAPI, IsCAR: carExport, } updates, err := client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref) + if err != nil { + t.Fatal(err) + } for update := range updates { if update.Err != "" { - t.Fatalf("%v", err) + t.Fatalf("retrieval failed: %s", update.Err) } } diff --git a/api/test/paych.go b/api/test/paych.go index 15ce352bd..e95773b6a 100644 --- a/api/test/paych.go +++ b/api/test/paych.go @@ -8,17 +8,21 @@ import ( "testing" "time" - "github.com/filecoin-project/specs-actors/actors/builtin" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" + cbor "github.com/ipfs/go-ipld-cbor" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/apibstore" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/events/state" "github.com/filecoin-project/lotus/chain/types" @@ -133,17 +137,26 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) { t.Fatal("Unable to settle payment channel") } + creatorStore := adt.WrapStore(ctx, cbor.NewCborStore(apibstore.NewAPIBlockstore(paymentCreator))) + // wait for the receiver to submit their vouchers ev := events.NewEvents(ctx, paymentCreator) preds := state.NewStatePredicates(paymentCreator) finished := make(chan struct{}) err = ev.StateChanged(func(ts *types.TipSet) (done bool, more bool, err error) { - act, err := paymentCreator.StateReadState(ctx, channel, ts.Key()) + act, err := paymentCreator.StateGetActor(ctx, channel, ts.Key()) if err != nil { return false, false, err } - state := act.State.(paych.State) - if state.ToSend.GreaterThanEqual(abi.NewTokenAmount(6000)) { + state, err := paych.Load(creatorStore, act) + if err != nil { + return false, false, err + } + toSend, err := state.ToSend() + if err != nil { + return false, false, err + } + if toSend.GreaterThanEqual(abi.NewTokenAmount(6000)) { return true, false, nil } return false, true, nil @@ -156,7 +169,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) { return true, nil }, func(ctx context.Context, ts *types.TipSet) error { return nil - }, int(build.MessageConfidence)+1, build.SealRandomnessLookbackLimit, func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) { + }, int(build.MessageConfidence)+1, build.Finality, func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) { return preds.OnPaymentChannelActorChanged(channel, preds.OnToSendAmountChanges())(ctx, oldTs.Key(), newTs.Key()) }) if err != nil { @@ -215,7 +228,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) { } // wait for the settlement period to pass before collecting - waitForBlocks(ctx, t, bm, paymentReceiver, receiverAddr, paych.SettleDelay) + waitForBlocks(ctx, t, bm, paymentReceiver, receiverAddr, paych0.SettleDelay) creatorPreCollectBalance, err := paymentCreator.WalletBalance(ctx, createrAddr) if err != nil { @@ -271,7 +284,7 @@ func waitForBlocks(ctx context.Context, t *testing.T, bm *BlockMiner, paymentRec // Add a real block m, err := paymentReceiver.MpoolPushMessage(ctx, &types.Message{ - To: builtin.BurntFundsActorAddr, + To: builtin0.BurntFundsActorAddr, From: receiverAddr, Value: types.NewInt(0), }, nil) diff --git a/api/test/test.go b/api/test/test.go index 409274ff1..853267eff 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -12,6 +12,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/miner" + "github.com/filecoin-project/lotus/node" ) type TestNode struct { @@ -44,7 +45,7 @@ type StorageMiner struct { // // storage array defines storage nodes, numbers in the array specify full node // index the storage node 'belongs' to -type APIBuilder func(t *testing.T, nFull int, storage []StorageMiner) ([]TestNode, []TestStorageNode) +type APIBuilder func(t *testing.T, nFull int, storage []StorageMiner, opts ...node.Option) ([]TestNode, []TestStorageNode) type testSuite struct { makeNodes APIBuilder } diff --git a/api/test/window_post.go b/api/test/window_post.go index 958c91816..eadcdbb05 100644 --- a/api/test/window_post.go +++ b/api/test/window_post.go @@ -15,9 +15,11 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/mock" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" + "github.com/filecoin-project/lotus/node" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" bminer "github.com/filecoin-project/lotus/miner" "github.com/filecoin-project/lotus/node/impl" @@ -114,8 +116,29 @@ func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n, } func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) { - ctx := context.Background() - n, sn := b(t, 1, OneMiner) + for _, height := range []abi.ChainEpoch{ + 1, // before + 162, // while sealing + 5000, // while proving + } { + height := height // copy to satisfy lints + t.Run(fmt.Sprintf("upgrade-%d", height), func(t *testing.T) { + testWindowPostUpgrade(t, b, blocktime, nSectors, height) + }) + } + +} +func testWindowPostUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int, + upgradeHeight abi.ChainEpoch) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{ + Network: build.ActorUpgradeNetworkVersion, + Height: upgradeHeight, + Migration: stmgr.UpgradeActorsV2, + }})) + client := n[0].FullNode.(*impl.FullNodeAPI) miner := sn[0] @@ -129,17 +152,24 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector } build.Clock.Sleep(time.Second) - mine := true done := make(chan struct{}) go func() { defer close(done) - for mine { + for ctx.Err() == nil { build.Clock.Sleep(blocktime) if err := sn[0].MineOne(ctx, MineNext); err != nil { + if ctx.Err() != nil { + // context was canceled, ignore the error. + return + } t.Error(err) } } }() + defer func() { + cancel() + <-done + }() pledgeSectors(t, ctx, miner, nSectors, 0, nil) @@ -159,7 +189,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector head, err := client.ChainHead(ctx) require.NoError(t, err) - if head.Height() > di.PeriodStart+(di.WPoStProvingPeriod)+2 { + if head.Height() > di.PeriodStart+di.WPoStProvingPeriod+2 { fmt.Printf("Now head.Height = %d\n", head.Height()) break } @@ -289,12 +319,11 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector pledgeSectors(t, ctx, miner, 1, nSectors, nil) { - // wait a bit more - - head, err := client.ChainHead(ctx) + // Wait until proven. + di, err = client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) require.NoError(t, err) - waitUntil := head.Height() + 10 + waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2 fmt.Printf("End for head.Height > %d\n", waitUntil) for { @@ -315,7 +344,4 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector sectors = p.MinerPower.RawBytePower.Uint64() / uint64(ssz) require.Equal(t, nSectors+GenesisPreseals-2+1, int(sectors)) // -2 not recovered sectors + 1 just pledged - - mine = false - <-done } diff --git a/build/params_2k.go b/build/params_2k.go index 3682f7be1..f4a17f724 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -14,6 +14,7 @@ const BreezeGasTampingDuration = 0 const UpgradeSmokeHeight = -1 const UpgradeIgnitionHeight = -2 const UpgradeLiftoffHeight = -3 +const UpgradeActorsV2Height = 10 var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, diff --git a/build/params_shared_funcs.go b/build/params_shared_funcs.go index 28567d3d1..40ccca50b 100644 --- a/build/params_shared_funcs.go +++ b/build/params_shared_funcs.go @@ -41,7 +41,7 @@ func DhtProtocolName(netName dtypes.NetworkName) protocol.ID { func UseNewestNetwork() bool { // TODO: Put these in a container we can iterate over - if UpgradeBreezeHeight <= 0 && UpgradeSmokeHeight <= 0 { + if UpgradeBreezeHeight <= 0 && UpgradeSmokeHeight <= 0 && UpgradeActorsV2Height <= 0 { return true } return false diff --git a/build/params_shared_vals.go b/build/params_shared_vals.go index 33828f954..4734a15ed 100644 --- a/build/params_shared_vals.go +++ b/build/params_shared_vals.go @@ -7,12 +7,12 @@ import ( "os" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" - miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) // ///// @@ -25,7 +25,7 @@ const UnixfsLinksPerLevel = 1024 // Consensus / Network const AllowableClockDriftSecs = uint64(1) -const NewestNetworkVersion = network.Version3 +const NewestNetworkVersion = network.Version4 const ActorUpgradeNetworkVersion = network.Version4 // Epochs @@ -35,7 +35,7 @@ const ForkLengthThreshold = Finality var BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch) // Epochs -const Finality = miner0.ChainFinality +const Finality = policy.ChainFinality const MessageConfidence = uint64(5) // constants for Weight calculation @@ -47,13 +47,8 @@ const WRatioDen = uint64(2) // Proofs // Epochs -const SealRandomnessLookback = Finality - -// Epochs -const SealRandomnessLookbackLimit = SealRandomnessLookback + 2000 // TODO: Get from spec specs-actors - -// Maximum lookback that randomness can be sourced from for a seal proof submission -const MaxSealLookback = SealRandomnessLookbackLimit + 2000 // TODO: Get from specs-actors +// TODO: unused +const SealRandomnessLookback = policy.SealRandomnessLookback // ///// // Mining diff --git a/build/params_testground.go b/build/params_testground.go index 07cc88688..6d51100e4 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -13,7 +13,8 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/specs-actors/actors/builtin" - miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + + "github.com/filecoin-project/lotus/chain/actors/policy" ) var ( @@ -32,7 +33,7 @@ var ( AllowableClockDriftSecs = uint64(1) - Finality = miner0.ChainFinality + Finality = policy.ChainFinality ForkLengthThreshold = Finality SlashablePowerDelay = 20 @@ -47,9 +48,7 @@ var ( BlsSignatureCacheSize = 40000 VerifSigCacheSize = 32000 - SealRandomnessLookback = Finality - SealRandomnessLookbackLimit = SealRandomnessLookback + 2000 - MaxSealLookback = SealRandomnessLookbackLimit + 2000 + SealRandomnessLookback = policy.SealRandomnessLookback TicketRandomnessLookback = abi.ChainEpoch(1) WinningPoStSectorSetLookback = abi.ChainEpoch(10) @@ -77,13 +76,14 @@ var ( UpgradeSmokeHeight abi.ChainEpoch = -1 UpgradeIgnitionHeight abi.ChainEpoch = -2 UpgradeLiftoffHeight abi.ChainEpoch = -3 + UpgradeActorsV2Height abi.ChainEpoch = 10 DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, } - NewestNetworkVersion = network.Version2 - ActorUpgradeNetworkVersion = network.Version3 + NewestNetworkVersion = network.Version4 + ActorUpgradeNetworkVersion = network.Version4 Devnet = true ) diff --git a/build/params_testnet.go b/build/params_testnet.go index 960f3a9b6..0aa77788b 100644 --- a/build/params_testnet.go +++ b/build/params_testnet.go @@ -23,6 +23,9 @@ const UpgradeSmokeHeight = 51000 const UpgradeIgnitionHeight = 94000 +// TODO: Actual epoch needs to be filled in +const UpgradeActorsV2Height = 128888 + // This signals our tentative epoch for mainnet launch. Can make it later, but not earlier. // Miners, clients, developers, custodians all need time to prepare. // We still have upgrades and state changes to do, but can happen after signaling timing here. diff --git a/chain/actors/adt/adt.go b/chain/actors/adt/adt.go index 39dd5cebc..6a454ac26 100644 --- a/chain/actors/adt/adt.go +++ b/chain/actors/adt/adt.go @@ -7,8 +7,11 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/network" - "github.com/filecoin-project/lotus/chain/actors/builtin" + + "github.com/filecoin-project/lotus/chain/actors" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" ) type Map interface { @@ -21,18 +24,22 @@ type Map interface { ForEach(v cbor.Unmarshaler, fn func(key string) error) error } -func AsMap(store Store, root cid.Cid, version builtin.Version) (Map, error) { +func AsMap(store Store, root cid.Cid, version actors.Version) (Map, error) { switch version { - case builtin.Version0: + case actors.Version0: return adt0.AsMap(store, root) + case actors.Version2: + return adt2.AsMap(store, root) } return nil, xerrors.Errorf("unknown network version: %d", version) } -func NewMap(store Store, version builtin.Version) (Map, error) { +func NewMap(store Store, version actors.Version) (Map, error) { switch version { - case builtin.Version0: + case actors.Version0: return adt0.MakeEmptyMap(store), nil + case actors.Version2: + return adt2.MakeEmptyMap(store), nil } return nil, xerrors.Errorf("unknown network version: %d", version) } @@ -49,17 +56,21 @@ type Array interface { } func AsArray(store Store, root cid.Cid, version network.Version) (Array, error) { - switch builtin.VersionForNetwork(version) { - case builtin.Version0: + switch actors.VersionForNetwork(version) { + case actors.Version0: return adt0.AsArray(store, root) + case actors.Version2: + return adt2.AsArray(store, root) } return nil, xerrors.Errorf("unknown network version: %d", version) } -func NewArray(store Store, version builtin.Version) (Array, error) { +func NewArray(store Store, version actors.Version) (Array, error) { switch version { - case builtin.Version0: + case actors.Version0: return adt0.MakeEmptyArray(store), nil + case actors.Version2: + return adt2.MakeEmptyArray(store), nil } return nil, xerrors.Errorf("unknown network version: %d", version) } diff --git a/chain/actors/builtin/account/account.go b/chain/actors/builtin/account/account.go index 5b90580ec..7b1b2a792 100644 --- a/chain/actors/builtin/account/account.go +++ b/chain/actors/builtin/account/account.go @@ -5,21 +5,31 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/cbor" - builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/ipfs/go-cid" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" ) +func init() { + builtin.RegisterActorState(builtin0.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load0(store, root) + }) + builtin.RegisterActorState(builtin2.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load2(store, root) + }) +} + func Load(store adt.Store, act *types.Actor) (State, error) { switch act.Code { case builtin0.AccountActorCodeID: - out := state0{store: store} - err := store.Get(store.Context(), act.Head, &out) - if err != nil { - return nil, err - } - return &out, nil + return load0(store, act.Head) + case builtin2.AccountActorCodeID: + return load2(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/account/v0.go b/chain/actors/builtin/account/v0.go index 30bafbfd3..67c555c5d 100644 --- a/chain/actors/builtin/account/v0.go +++ b/chain/actors/builtin/account/v0.go @@ -2,14 +2,26 @@ package account import ( "github.com/filecoin-project/go-address" + "github.com/ipfs/go-cid" + "github.com/filecoin-project/lotus/chain/actors/adt" - "github.com/filecoin-project/specs-actors/actors/builtin/account" + + account0 "github.com/filecoin-project/specs-actors/actors/builtin/account" ) var _ State = (*state0)(nil) +func load0(store adt.Store, root cid.Cid) (State, error) { + out := state0{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + type state0 struct { - account.State + account0.State store adt.Store } diff --git a/chain/actors/builtin/account/v2.go b/chain/actors/builtin/account/v2.go new file mode 100644 index 000000000..2664631bc --- /dev/null +++ b/chain/actors/builtin/account/v2.go @@ -0,0 +1,30 @@ +package account + +import ( + "github.com/filecoin-project/go-address" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" + + account2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/account" +) + +var _ State = (*state2)(nil) + +func load2(store adt.Store, root cid.Cid) (State, error) { + out := state2{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state2 struct { + account2.State + store adt.Store +} + +func (s *state2) PubkeyAddress() (address.Address, error) { + return s.Address, nil +} diff --git a/chain/actors/builtin/builtin.go b/chain/actors/builtin/builtin.go index a85b4da65..d49164486 100644 --- a/chain/actors/builtin/builtin.go +++ b/chain/actors/builtin/builtin.go @@ -1,32 +1,25 @@ package builtin import ( - "fmt" + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/cbor" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof" - smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing" - - "github.com/filecoin-project/go-state-types/network" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing" ) -type Version int - -const ( - Version0 = iota -) - -// Converts a network version into a specs-actors version. -func VersionForNetwork(version network.Version) Version { - switch version { - case network.Version0, network.Version1, network.Version2, network.Version3: - return Version0 - default: - panic(fmt.Sprintf("unsupported network version %d", version)) - } -} +var SystemActorAddr = builtin0.SystemActorAddr +var BurntFundsActorAddr = builtin0.BurntFundsActorAddr // TODO: Why does actors have 2 different versions of this? type SectorInfo = proof0.SectorInfo @@ -41,3 +34,55 @@ func FromV0FilterEstimate(v0 smoothing0.FilterEstimate) FilterEstimate { func QAPowerForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, verifiedWeight abi.DealWeight) abi.StoragePower { return miner0.QAPowerForWeight(size, duration, dealWeight, verifiedWeight) } + +func FromV2FilterEstimate(v1 smoothing2.FilterEstimate) FilterEstimate { + return (FilterEstimate)(v1) +} + +type ActorStateLoader func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) + +var ActorStateLoaders = make(map[cid.Cid]ActorStateLoader) + +func RegisterActorState(code cid.Cid, loader ActorStateLoader) { + ActorStateLoaders[code] = loader +} + +func Load(store adt.Store, act *types.Actor) (cbor.Marshaler, error) { + loader, found := ActorStateLoaders[act.Code] + if !found { + return nil, xerrors.Errorf("unknown actor code %s", act.Code) + } + return loader(store, act.Head) +} + +func ActorNameByCode(c cid.Cid) string { + switch { + case builtin0.IsBuiltinActor(c): + return builtin0.ActorNameByCode(c) + case builtin2.IsBuiltinActor(c): + return builtin2.ActorNameByCode(c) + default: + return "" + } +} + +func IsBuiltinActor(c cid.Cid) bool { + return builtin0.IsBuiltinActor(c) || builtin2.IsBuiltinActor(c) +} + +func IsAccountActor(c cid.Cid) bool { + return c == builtin0.AccountActorCodeID || c == builtin2.AccountActorCodeID +} + +func IsStorageMinerActor(c cid.Cid) bool { + return c == builtin0.StorageMinerActorCodeID || c == builtin2.StorageMinerActorCodeID +} + +func IsMultisigActor(c cid.Cid) bool { + return c == builtin0.MultisigActorCodeID || c == builtin2.MultisigActorCodeID + +} + +func IsPaymentChannelActor(c cid.Cid) bool { + return c == builtin0.PaymentChannelActorCodeID || c == builtin2.PaymentChannelActorCodeID +} diff --git a/chain/actors/builtin/init/init.go b/chain/actors/builtin/init/init.go index f235450c2..5777bb890 100644 --- a/chain/actors/builtin/init/init.go +++ b/chain/actors/builtin/init/init.go @@ -6,24 +6,34 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/cbor" - builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/ipfs/go-cid" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/modules/dtypes" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" ) +func init() { + builtin.RegisterActorState(builtin0.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load0(store, root) + }) + builtin.RegisterActorState(builtin2.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load2(store, root) + }) +} + var Address = builtin0.InitActorAddr func Load(store adt.Store, act *types.Actor) (State, error) { switch act.Code { case builtin0.InitActorCodeID: - out := state0{store: store} - err := store.Get(store.Context(), act.Head, &out) - if err != nil { - return nil, err - } - return &out, nil + return load0(store, act.Head) + case builtin2.InitActorCodeID: + return load2(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -41,4 +51,7 @@ type State interface { // It should not be used in production code, as init actor entries are // immutable. Remove(addrs ...address.Address) error + + // Sets the network's name. This should only be used on upgrade/fork. + SetNetworkName(name string) error } diff --git a/chain/actors/builtin/init/v0.go b/chain/actors/builtin/init/v0.go index 425ba654c..ceb87f970 100644 --- a/chain/actors/builtin/init/v0.go +++ b/chain/actors/builtin/init/v0.go @@ -3,21 +3,30 @@ package init import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" - init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/node/modules/dtypes" + init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" ) var _ State = (*state0)(nil) +func load0(store adt.Store, root cid.Cid) (State, error) { + out := state0{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + type state0 struct { - init_.State + init0.State store adt.Store } @@ -48,6 +57,11 @@ func (s *state0) NetworkName() (dtypes.NetworkName, error) { return dtypes.NetworkName(s.State.NetworkName), nil } +func (s *state0) SetNetworkName(name string) error { + s.State.NetworkName = name + return nil +} + func (s *state0) Remove(addrs ...address.Address) (err error) { m, err := adt0.AsMap(s.store, s.State.AddressMap) if err != nil { diff --git a/chain/actors/builtin/init/v2.go b/chain/actors/builtin/init/v2.go new file mode 100644 index 000000000..5aa0ddc18 --- /dev/null +++ b/chain/actors/builtin/init/v2.go @@ -0,0 +1,81 @@ +package init + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/node/modules/dtypes" + + init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" + adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" +) + +var _ State = (*state2)(nil) + +func load2(store adt.Store, root cid.Cid) (State, error) { + out := state2{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state2 struct { + init2.State + store adt.Store +} + +func (s *state2) ResolveAddress(address address.Address) (address.Address, bool, error) { + return s.State.ResolveAddress(s.store, address) +} + +func (s *state2) MapAddressToNewID(address address.Address) (address.Address, error) { + return s.State.MapAddressToNewID(s.store, address) +} + +func (s *state2) ForEachActor(cb func(id abi.ActorID, address address.Address) error) error { + addrs, err := adt2.AsMap(s.store, s.State.AddressMap) + if err != nil { + return err + } + var actorID cbg.CborInt + return addrs.ForEach(&actorID, func(key string) error { + addr, err := address.NewFromBytes([]byte(key)) + if err != nil { + return err + } + return cb(abi.ActorID(actorID), addr) + }) +} + +func (s *state2) NetworkName() (dtypes.NetworkName, error) { + return dtypes.NetworkName(s.State.NetworkName), nil +} + +func (s *state2) SetNetworkName(name string) error { + s.State.NetworkName = name + return nil +} + +func (s *state2) Remove(addrs ...address.Address) (err error) { + m, err := adt2.AsMap(s.store, s.State.AddressMap) + if err != nil { + return err + } + for _, addr := range addrs { + if err = m.Delete(abi.AddrKey(addr)); err != nil { + return xerrors.Errorf("failed to delete entry for address: %s; err: %w", addr, err) + } + } + amr, err := m.Root() + if err != nil { + return xerrors.Errorf("failed to get address map root: %w", err) + } + s.State.AddressMap = amr + return nil +} diff --git a/chain/actors/builtin/market/market.go b/chain/actors/builtin/market/market.go index fef0c03f9..fd08a0119 100644 --- a/chain/actors/builtin/market/market.go +++ b/chain/actors/builtin/market/market.go @@ -6,26 +6,35 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/cbor" - builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" - market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" ) +func init() { + builtin.RegisterActorState(builtin0.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load0(store, root) + }) + builtin.RegisterActorState(builtin2.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load2(store, root) + }) +} + var Address = builtin0.StorageMarketActorAddr func Load(store adt.Store, act *types.Actor) (st State, err error) { switch act.Code { case builtin0.StorageMarketActorCodeID: - out := state0{store: store} - err := store.Get(store.Context(), act.Head, &out) - if err != nil { - return nil, err - } - return &out, nil + return load0(store, act.Head) + case builtin2.StorageMarketActorCodeID: + return load2(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/market/v0.go b/chain/actors/builtin/market/v0.go index 2727f513d..20d38b5f1 100644 --- a/chain/actors/builtin/market/v0.go +++ b/chain/actors/builtin/market/v0.go @@ -5,17 +5,29 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/builtin/market" + + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" - cbg "github.com/whyrusleeping/cbor-gen" ) var _ State = (*state0)(nil) +func load0(store adt.Store, root cid.Cid) (State, error) { + out := state0{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + type state0 struct { - market.State + market0.State store adt.Store } @@ -90,7 +102,7 @@ func (s *state0) LockedTable() (BalanceTable, error) { func (s *state0) VerifyDealsForActivation( minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch, ) (weight, verifiedWeight abi.DealWeight, err error) { - return market.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch) + return market0.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch) } type balanceTable0 struct { @@ -114,7 +126,7 @@ type dealStates0 struct { } func (s *dealStates0) Get(dealID abi.DealID) (*DealState, bool, error) { - var deal0 market.DealState + var deal0 market0.DealState found, err := s.Array.Get(uint64(dealID), &deal0) if err != nil { return nil, false, err @@ -127,14 +139,14 @@ func (s *dealStates0) Get(dealID abi.DealID) (*DealState, bool, error) { } func (s *dealStates0) ForEach(cb func(dealID abi.DealID, ds DealState) error) error { - var ds0 market.DealState + var ds0 market0.DealState return s.Array.ForEach(&ds0, func(idx int64) error { return cb(abi.DealID(idx), fromV0DealState(ds0)) }) } func (s *dealStates0) decode(val *cbg.Deferred) (*DealState, error) { - var ds0 market.DealState + var ds0 market0.DealState if err := ds0.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { return nil, err } @@ -146,7 +158,7 @@ func (s *dealStates0) array() adt.Array { return s.Array } -func fromV0DealState(v0 market.DealState) DealState { +func fromV0DealState(v0 market0.DealState) DealState { return (DealState)(v0) } @@ -155,7 +167,7 @@ type dealProposals0 struct { } func (s *dealProposals0) Get(dealID abi.DealID) (*DealProposal, bool, error) { - var proposal0 market.DealProposal + var proposal0 market0.DealProposal found, err := s.Array.Get(uint64(dealID), &proposal0) if err != nil { return nil, false, err @@ -168,14 +180,14 @@ func (s *dealProposals0) Get(dealID abi.DealID) (*DealProposal, bool, error) { } func (s *dealProposals0) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error { - var dp0 market.DealProposal + var dp0 market0.DealProposal return s.Array.ForEach(&dp0, func(idx int64) error { return cb(abi.DealID(idx), fromV0DealProposal(dp0)) }) } func (s *dealProposals0) decode(val *cbg.Deferred) (*DealProposal, error) { - var dp0 market.DealProposal + var dp0 market0.DealProposal if err := dp0.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { return nil, err } @@ -187,6 +199,6 @@ func (s *dealProposals0) array() adt.Array { return s.Array } -func fromV0DealProposal(v0 market.DealProposal) DealProposal { +func fromV0DealProposal(v0 market0.DealProposal) DealProposal { return (DealProposal)(v0) } diff --git a/chain/actors/builtin/market/v2.go b/chain/actors/builtin/market/v2.go new file mode 100644 index 000000000..a5e5c7b45 --- /dev/null +++ b/chain/actors/builtin/market/v2.go @@ -0,0 +1,205 @@ +package market + +import ( + "bytes" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" + + market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" + adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" +) + +var _ State = (*state2)(nil) + +func load2(store adt.Store, root cid.Cid) (State, error) { + out := state2{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state2 struct { + market2.State + store adt.Store +} + +func (s *state2) TotalLocked() (abi.TokenAmount, error) { + fml := types.BigAdd(s.TotalClientLockedCollateral, s.TotalProviderLockedCollateral) + fml = types.BigAdd(fml, s.TotalClientStorageFee) + return fml, nil +} + +func (s *state2) BalancesChanged(otherState State) (bool, error) { + otherState2, ok := otherState.(*state2) + if !ok { + // there's no way to compare different versions of the state, so let's + // just say that means the state of balances has changed + return true, nil + } + return !s.State.EscrowTable.Equals(otherState2.State.EscrowTable) || !s.State.LockedTable.Equals(otherState2.State.LockedTable), nil +} + +func (s *state2) StatesChanged(otherState State) (bool, error) { + otherState2, ok := otherState.(*state2) + if !ok { + // there's no way to compare different versions of the state, so let's + // just say that means the state of balances has changed + return true, nil + } + return !s.State.States.Equals(otherState2.State.States), nil +} + +func (s *state2) States() (DealStates, error) { + stateArray, err := adt2.AsArray(s.store, s.State.States) + if err != nil { + return nil, err + } + return &dealStates2{stateArray}, nil +} + +func (s *state2) ProposalsChanged(otherState State) (bool, error) { + otherState2, ok := otherState.(*state2) + if !ok { + // there's no way to compare different versions of the state, so let's + // just say that means the state of balances has changed + return true, nil + } + return !s.State.Proposals.Equals(otherState2.State.Proposals), nil +} + +func (s *state2) Proposals() (DealProposals, error) { + proposalArray, err := adt2.AsArray(s.store, s.State.Proposals) + if err != nil { + return nil, err + } + return &dealProposals2{proposalArray}, nil +} + +func (s *state2) EscrowTable() (BalanceTable, error) { + bt, err := adt2.AsBalanceTable(s.store, s.State.EscrowTable) + if err != nil { + return nil, err + } + return &balanceTable2{bt}, nil +} + +func (s *state2) LockedTable() (BalanceTable, error) { + bt, err := adt2.AsBalanceTable(s.store, s.State.LockedTable) + if err != nil { + return nil, err + } + return &balanceTable2{bt}, nil +} + +func (s *state2) VerifyDealsForActivation( + minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch, +) (weight, verifiedWeight abi.DealWeight, err error) { + w, vw, _, err := market2.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch) + return w, vw, err +} + +type balanceTable2 struct { + *adt2.BalanceTable +} + +func (bt *balanceTable2) ForEach(cb func(address.Address, abi.TokenAmount) error) error { + asMap := (*adt2.Map)(bt.BalanceTable) + var ta abi.TokenAmount + return asMap.ForEach(&ta, func(key string) error { + a, err := address.NewFromBytes([]byte(key)) + if err != nil { + return err + } + return cb(a, ta) + }) +} + +type dealStates2 struct { + adt.Array +} + +func (s *dealStates2) Get(dealID abi.DealID) (*DealState, bool, error) { + var deal2 market2.DealState + found, err := s.Array.Get(uint64(dealID), &deal2) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + deal := fromV2DealState(deal2) + return &deal, true, nil +} + +func (s *dealStates2) ForEach(cb func(dealID abi.DealID, ds DealState) error) error { + var ds1 market2.DealState + return s.Array.ForEach(&ds1, func(idx int64) error { + return cb(abi.DealID(idx), fromV2DealState(ds1)) + }) +} + +func (s *dealStates2) decode(val *cbg.Deferred) (*DealState, error) { + var ds1 market2.DealState + if err := ds1.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + ds := fromV2DealState(ds1) + return &ds, nil +} + +func (s *dealStates2) array() adt.Array { + return s.Array +} + +func fromV2DealState(v1 market2.DealState) DealState { + return (DealState)(v1) +} + +type dealProposals2 struct { + adt.Array +} + +func (s *dealProposals2) Get(dealID abi.DealID) (*DealProposal, bool, error) { + var proposal2 market2.DealProposal + found, err := s.Array.Get(uint64(dealID), &proposal2) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + proposal := fromV2DealProposal(proposal2) + return &proposal, true, nil +} + +func (s *dealProposals2) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error { + var dp1 market2.DealProposal + return s.Array.ForEach(&dp1, func(idx int64) error { + return cb(abi.DealID(idx), fromV2DealProposal(dp1)) + }) +} + +func (s *dealProposals2) decode(val *cbg.Deferred) (*DealProposal, error) { + var dp1 market2.DealProposal + if err := dp1.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + dp := fromV2DealProposal(dp1) + return &dp, nil +} + +func (s *dealProposals2) array() adt.Array { + return s.Array +} + +func fromV2DealProposal(v1 market2.DealProposal) DealProposal { + return (DealProposal)(v1) +} diff --git a/chain/actors/builtin/miner/miner.go b/chain/actors/builtin/miner/miner.go index 5ea5cfc81..125d142d3 100644 --- a/chain/actors/builtin/miner/miner.go +++ b/chain/actors/builtin/miner/miner.go @@ -11,14 +11,26 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/dline" - builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" - miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" ) -// Unchanged between v0 and v1 actors +func init() { + builtin.RegisterActorState(builtin0.StorageMinerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load0(store, root) + }) + builtin.RegisterActorState(builtin2.StorageMinerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load2(store, root) + }) +} + +// Unchanged between v0 and v2 actors var WPoStProvingPeriod = miner0.WPoStProvingPeriod var WPoStPeriodDeadlines = miner0.WPoStPeriodDeadlines var WPoStChallengeWindow = miner0.WPoStChallengeWindow @@ -30,12 +42,9 @@ const MinSectorExpiration = miner0.MinSectorExpiration func Load(store adt.Store, act *types.Actor) (st State, err error) { switch act.Code { case builtin0.StorageMinerActorCodeID: - out := state0{store: store} - err := store.Get(store.Context(), act.Head, &out) - if err != nil { - return nil, err - } - return &out, nil + return load0(store, act.Head) + case builtin2.StorageMinerActorCodeID: + return load2(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/miner/v0.go b/chain/actors/builtin/miner/v0.go index f5aa7849d..902ed20f2 100644 --- a/chain/actors/builtin/miner/v0.go +++ b/chain/actors/builtin/miner/v0.go @@ -4,22 +4,32 @@ import ( "bytes" "errors" - "github.com/libp2p/go-libp2p-core/peer" - cbg "github.com/whyrusleeping/cbor-gen" - "golang.org/x/xerrors" - "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/dline" - miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" - adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/ipfs/go-cid" + "github.com/libp2p/go-libp2p-core/peer" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/actors/adt" + + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" ) var _ State = (*state0)(nil) +func load0(store adt.Store, root cid.Cid) (State, error) { + out := state0{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + type state0 struct { miner0.State store adt.Store diff --git a/chain/actors/builtin/miner/v2.go b/chain/actors/builtin/miner/v2.go new file mode 100644 index 000000000..934554d23 --- /dev/null +++ b/chain/actors/builtin/miner/v2.go @@ -0,0 +1,402 @@ +package miner + +import ( + "bytes" + "errors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/dline" + "github.com/ipfs/go-cid" + "github.com/libp2p/go-libp2p-core/peer" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors/adt" + + miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" + adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" +) + +var _ State = (*state2)(nil) + +func load2(store adt.Store, root cid.Cid) (State, error) { + out := state2{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state2 struct { + miner2.State + store adt.Store +} + +type deadline2 struct { + miner2.Deadline + store adt.Store +} + +type partition2 struct { + miner2.Partition + store adt.Store +} + +func (s *state2) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) { + return s.GetAvailableBalance(bal), nil +} + +func (s *state2) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.CheckVestedFunds(s.store, epoch) +} + +func (s *state2) LockedFunds() (LockedFunds, error) { + return LockedFunds{ + VestingFunds: s.State.LockedFunds, + InitialPledgeRequirement: s.State.InitialPledge, + PreCommitDeposits: s.State.PreCommitDeposits, + }, nil +} + +func (s *state2) InitialPledge() (abi.TokenAmount, error) { + return s.State.InitialPledge, nil +} + +func (s *state2) PreCommitDeposits() (abi.TokenAmount, error) { + return s.State.PreCommitDeposits, nil +} + +func (s *state2) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { + info, ok, err := s.State.GetSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV2SectorOnChainInfo(*info) + return &ret, nil +} + +func (s *state2) FindSector(num abi.SectorNumber) (*SectorLocation, error) { + dlIdx, partIdx, err := s.State.FindSector(s.store, num) + if err != nil { + return nil, err + } + return &SectorLocation{ + Deadline: dlIdx, + Partition: partIdx, + }, nil +} + +func (s *state2) NumLiveSectors() (uint64, error) { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return 0, err + } + var total uint64 + if err := dls.ForEach(s.store, func(dlIdx uint64, dl *miner2.Deadline) error { + total += dl.LiveSectors + return nil + }); err != nil { + return 0, err + } + return total, nil +} + +// GetSectorExpiration returns the effective expiration of the given sector. +// +// If the sector does not expire early, the Early expiration field is 0. +func (s *state2) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, error) { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return nil, err + } + // NOTE: this can be optimized significantly. + // 1. If the sector is non-faulty, it will either expire on-time (can be + // learned from the sector info), or in the next quantized expiration + // epoch (i.e., the first element in the partition's expiration queue. + // 2. If it's faulty, it will expire early within the first 14 entries + // of the expiration queue. + stopErr := errors.New("stop") + out := SectorExpiration{} + err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner2.Deadline) error { + partitions, err := dl.PartitionsArray(s.store) + if err != nil { + return err + } + quant := s.State.QuantSpecForDeadline(dlIdx) + var part miner2.Partition + return partitions.ForEach(&part, func(partIdx int64) error { + if found, err := part.Sectors.IsSet(uint64(num)); err != nil { + return err + } else if !found { + return nil + } + if found, err := part.Terminated.IsSet(uint64(num)); err != nil { + return err + } else if found { + // already terminated + return stopErr + } + + q, err := miner2.LoadExpirationQueue(s.store, part.ExpirationsEpochs, quant) + if err != nil { + return err + } + var exp miner2.ExpirationSet + return q.ForEach(&exp, func(epoch int64) error { + if early, err := exp.EarlySectors.IsSet(uint64(num)); err != nil { + return err + } else if early { + out.Early = abi.ChainEpoch(epoch) + return nil + } + if onTime, err := exp.OnTimeSectors.IsSet(uint64(num)); err != nil { + return err + } else if onTime { + out.OnTime = abi.ChainEpoch(epoch) + return stopErr + } + return nil + }) + }) + }) + if err == stopErr { + err = nil + } + if err != nil { + return nil, err + } + if out.Early == 0 && out.OnTime == 0 { + return nil, xerrors.Errorf("failed to find sector %d", num) + } + return &out, nil +} + +func (s *state2) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { + info, ok, err := s.State.GetPrecommittedSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV2SectorPreCommitOnChainInfo(*info) + + return &ret, nil +} + +func (s *state2) LoadSectors(snos *bitfield.BitField) ([]*SectorOnChainInfo, error) { + sectors, err := miner2.LoadSectors(s.store, s.State.Sectors) + if err != nil { + return nil, err + } + + // If no sector numbers are specified, load all. + if snos == nil { + infos := make([]*SectorOnChainInfo, 0, sectors.Length()) + var info2 miner2.SectorOnChainInfo + if err := sectors.ForEach(&info2, func(_ int64) error { + info := fromV2SectorOnChainInfo(info2) + infos = append(infos, &info) + return nil + }); err != nil { + return nil, err + } + return infos, nil + } + + // Otherwise, load selected. + infos2, err := sectors.Load(*snos) + if err != nil { + return nil, err + } + infos := make([]*SectorOnChainInfo, len(infos2)) + for i, info2 := range infos2 { + info := fromV2SectorOnChainInfo(*info2) + infos[i] = &info + } + return infos, nil +} + +func (s *state2) IsAllocated(num abi.SectorNumber) (bool, error) { + var allocatedSectors bitfield.BitField + if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil { + return false, err + } + + return allocatedSectors.IsSet(uint64(num)) +} + +func (s *state2) LoadDeadline(idx uint64) (Deadline, error) { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return nil, err + } + dl, err := dls.LoadDeadline(s.store, idx) + if err != nil { + return nil, err + } + return &deadline2{*dl, s.store}, nil +} + +func (s *state2) ForEachDeadline(cb func(uint64, Deadline) error) error { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return err + } + return dls.ForEach(s.store, func(i uint64, dl *miner2.Deadline) error { + return cb(i, &deadline2{*dl, s.store}) + }) +} + +func (s *state2) NumDeadlines() (uint64, error) { + return miner2.WPoStPeriodDeadlines, nil +} + +func (s *state2) DeadlinesChanged(other State) (bool, error) { + other2, ok := other.(*state2) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return s.State.Deadlines.Equals(other2.Deadlines), nil +} + +func (s *state2) Info() (MinerInfo, error) { + info, err := s.State.GetInfo(s.store) + if err != nil { + return MinerInfo{}, err + } + + var pid *peer.ID + if peerID, err := peer.IDFromBytes(info.PeerId); err == nil { + pid = &peerID + } + + mi := MinerInfo{ + Owner: info.Owner, + Worker: info.Worker, + ControlAddresses: info.ControlAddresses, + + NewWorker: address.Undef, + WorkerChangeEpoch: -1, + + PeerId: pid, + Multiaddrs: info.Multiaddrs, + SealProofType: info.SealProofType, + SectorSize: info.SectorSize, + WindowPoStPartitionSectors: info.WindowPoStPartitionSectors, + } + + if info.PendingWorkerKey != nil { + mi.NewWorker = info.PendingWorkerKey.NewWorker + mi.WorkerChangeEpoch = info.PendingWorkerKey.EffectiveAt + } + + return mi, nil +} + +func (s *state2) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) { + return s.State.DeadlineInfo(epoch), nil +} + +func (s *state2) sectors() (adt.Array, error) { + return adt2.AsArray(s.store, s.Sectors) +} + +func (s *state2) decodeSectorOnChainInfo(val *cbg.Deferred) (SectorOnChainInfo, error) { + var si miner2.SectorOnChainInfo + err := si.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorOnChainInfo{}, err + } + + return fromV2SectorOnChainInfo(si), nil +} + +func (s *state2) precommits() (adt.Map, error) { + return adt2.AsMap(s.store, s.PreCommittedSectors) +} + +func (s *state2) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { + var sp miner2.SectorPreCommitOnChainInfo + err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorPreCommitOnChainInfo{}, err + } + + return fromV2SectorPreCommitOnChainInfo(sp), nil +} + +func (d *deadline2) LoadPartition(idx uint64) (Partition, error) { + p, err := d.Deadline.LoadPartition(d.store, idx) + if err != nil { + return nil, err + } + return &partition2{*p, d.store}, nil +} + +func (d *deadline2) ForEachPartition(cb func(uint64, Partition) error) error { + ps, err := d.Deadline.PartitionsArray(d.store) + if err != nil { + return err + } + var part miner2.Partition + return ps.ForEach(&part, func(i int64) error { + return cb(uint64(i), &partition2{part, d.store}) + }) +} + +func (d *deadline2) PartitionsChanged(other Deadline) (bool, error) { + other2, ok := other.(*deadline2) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return d.Deadline.Partitions.Equals(other2.Deadline.Partitions), nil +} + +func (d *deadline2) PostSubmissions() (bitfield.BitField, error) { + return d.Deadline.PostSubmissions, nil +} + +func (p *partition2) AllSectors() (bitfield.BitField, error) { + return p.Partition.Sectors, nil +} + +func (p *partition2) FaultySectors() (bitfield.BitField, error) { + return p.Partition.Faults, nil +} + +func (p *partition2) RecoveringSectors() (bitfield.BitField, error) { + return p.Partition.Recoveries, nil +} + +func fromV2SectorOnChainInfo(v2 miner2.SectorOnChainInfo) SectorOnChainInfo { + return SectorOnChainInfo{ + SectorNumber: v2.SectorNumber, + SealProof: v2.SealProof, + SealedCID: v2.SealedCID, + DealIDs: v2.DealIDs, + Activation: v2.Activation, + Expiration: v2.Expiration, + DealWeight: v2.DealWeight, + VerifiedDealWeight: v2.VerifiedDealWeight, + InitialPledge: v2.InitialPledge, + ExpectedDayReward: v2.ExpectedDayReward, + ExpectedStoragePledge: v2.ExpectedStoragePledge, + } +} + +func fromV2SectorPreCommitOnChainInfo(v2 miner2.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + return SectorPreCommitOnChainInfo{ + Info: (SectorPreCommitInfo)(v2.Info), + PreCommitDeposit: v2.PreCommitDeposit, + PreCommitEpoch: v2.PreCommitEpoch, + DealWeight: v2.DealWeight, + VerifiedDealWeight: v2.VerifiedDealWeight, + } +} diff --git a/chain/actors/builtin/multisig/message.go b/chain/actors/builtin/multisig/message.go new file mode 100644 index 000000000..b19287432 --- /dev/null +++ b/chain/actors/builtin/multisig/message.go @@ -0,0 +1,70 @@ +package multisig + +import ( + "fmt" + + "github.com/minio/blake2b-simd" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + multisig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" +) + +func Message(version actors.Version, from address.Address) MessageBuilder { + switch version { + case actors.Version0: + return message0{from} + case actors.Version2: + return message2{message0{from}} + default: + panic(fmt.Sprintf("unsupported actors version: %d", version)) + } +} + +type MessageBuilder interface { + // Create a new multisig with the specified parameters. + Create(signers []address.Address, threshold uint64, + vestingStart, vestingDuration abi.ChainEpoch, + initialAmount abi.TokenAmount) (*types.Message, error) + + // Propose a transaction to the given multisig. + Propose(msig, target address.Address, amt abi.TokenAmount, + method abi.MethodNum, params []byte) (*types.Message, error) + + // Approve a multisig transaction. The "hash" is optional. + Approve(msig address.Address, txID uint64, hash *ProposalHashData) (*types.Message, error) + + // Cancel a multisig transaction. The "hash" is optional. + Cancel(msig address.Address, txID uint64, hash *ProposalHashData) (*types.Message, error) +} + +// this type is the same between v0 and v2 +type ProposalHashData = multisig2.ProposalHashData + +func txnParams(id uint64, data *ProposalHashData) ([]byte, error) { + params := multisig2.TxnIDParams{ID: multisig2.TxnID(id)} + if data != nil { + if data.Requester.Protocol() != address.ID { + return nil, xerrors.Errorf("proposer address must be an ID address, was %s", data.Requester) + } + if data.Value.Sign() == -1 { + return nil, xerrors.Errorf("proposal value must be non-negative, was %s", data.Value) + } + if data.To == address.Undef { + return nil, xerrors.Errorf("proposed destination address must be set") + } + pser, err := data.Serialize() + if err != nil { + return nil, err + } + hash := blake2b.Sum256(pser) + params.ProposalHash = hash[:] + } + + return actors.SerializeParams(¶ms) +} diff --git a/chain/actors/builtin/multisig/message0.go b/chain/actors/builtin/multisig/message0.go new file mode 100644 index 000000000..dc43a9d5d --- /dev/null +++ b/chain/actors/builtin/multisig/message0.go @@ -0,0 +1,142 @@ +package multisig + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" + multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + + "github.com/filecoin-project/lotus/chain/actors" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/types" +) + +type message0 struct{ from address.Address } + +func (m message0) Create( + signers []address.Address, threshold uint64, + unlockStart, unlockDuration abi.ChainEpoch, + initialAmount abi.TokenAmount, +) (*types.Message, error) { + + lenAddrs := uint64(len(signers)) + + if lenAddrs < threshold { + return nil, xerrors.Errorf("cannot require signing of more addresses than provided for multisig") + } + + if threshold == 0 { + threshold = lenAddrs + } + + if m.from == address.Undef { + return nil, xerrors.Errorf("must provide source address") + } + + if unlockStart != 0 { + return nil, xerrors.Errorf("actors v0 does not support a non-zero vesting start time") + } + + // Set up constructor parameters for multisig + msigParams := &multisig0.ConstructorParams{ + Signers: signers, + NumApprovalsThreshold: threshold, + UnlockDuration: unlockDuration, + } + + enc, actErr := actors.SerializeParams(msigParams) + if actErr != nil { + return nil, actErr + } + + // new actors are created by invoking 'exec' on the init actor with the constructor params + execParams := &init0.ExecParams{ + CodeCID: builtin0.MultisigActorCodeID, + ConstructorParams: enc, + } + + enc, actErr = actors.SerializeParams(execParams) + if actErr != nil { + return nil, actErr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Method: builtin0.MethodsInit.Exec, + Params: enc, + Value: initialAmount, + }, nil +} + +func (m message0) Propose(msig, to address.Address, amt abi.TokenAmount, + method abi.MethodNum, params []byte) (*types.Message, error) { + + if msig == address.Undef { + return nil, xerrors.Errorf("must provide a multisig address for proposal") + } + + if to == address.Undef { + return nil, xerrors.Errorf("must provide a target address for proposal") + } + + if amt.Sign() == -1 { + return nil, xerrors.Errorf("must provide a non-negative amount for proposed send") + } + + if m.from == address.Undef { + return nil, xerrors.Errorf("must provide source address") + } + + enc, actErr := actors.SerializeParams(&multisig0.ProposeParams{ + To: to, + Value: amt, + Method: method, + Params: params, + }) + if actErr != nil { + return nil, xerrors.Errorf("failed to serialize parameters: %w", actErr) + } + + return &types.Message{ + To: msig, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin0.MethodsMultisig.Propose, + Params: enc, + }, nil +} + +func (m message0) Approve(msig address.Address, txID uint64, hashData *ProposalHashData) (*types.Message, error) { + enc, err := txnParams(txID, hashData) + if err != nil { + return nil, err + } + + return &types.Message{ + To: msig, + From: m.from, + Value: types.NewInt(0), + Method: builtin0.MethodsMultisig.Approve, + Params: enc, + }, nil +} + +func (m message0) Cancel(msig address.Address, txID uint64, hashData *ProposalHashData) (*types.Message, error) { + enc, err := txnParams(txID, hashData) + if err != nil { + return nil, err + } + + return &types.Message{ + To: msig, + From: m.from, + Value: types.NewInt(0), + Method: builtin0.MethodsMultisig.Cancel, + Params: enc, + }, nil +} diff --git a/chain/actors/builtin/multisig/message2.go b/chain/actors/builtin/multisig/message2.go new file mode 100644 index 000000000..da2700d06 --- /dev/null +++ b/chain/actors/builtin/multisig/message2.go @@ -0,0 +1,71 @@ +package multisig + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" + multisig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig" + + "github.com/filecoin-project/lotus/chain/actors" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/types" +) + +type message2 struct{ message0 } + +func (m message2) Create( + signers []address.Address, threshold uint64, + unlockStart, unlockDuration abi.ChainEpoch, + initialAmount abi.TokenAmount, +) (*types.Message, error) { + + lenAddrs := uint64(len(signers)) + + if lenAddrs < threshold { + return nil, xerrors.Errorf("cannot require signing of more addresses than provided for multisig") + } + + if threshold == 0 { + threshold = lenAddrs + } + + if m.from == address.Undef { + return nil, xerrors.Errorf("must provide source address") + } + + // Set up constructor parameters for multisig + msigParams := &multisig2.ConstructorParams{ + Signers: signers, + NumApprovalsThreshold: threshold, + UnlockDuration: unlockDuration, + StartEpoch: unlockStart, + } + + enc, actErr := actors.SerializeParams(msigParams) + if actErr != nil { + return nil, actErr + } + + // new actors are created by invoking 'exec' on the init actor with the constructor params + execParams := &init2.ExecParams{ + CodeCID: builtin2.MultisigActorCodeID, + ConstructorParams: enc, + } + + enc, actErr = actors.SerializeParams(execParams) + if actErr != nil { + return nil, actErr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Method: builtin2.MethodsInit.Exec, + Params: enc, + Value: initialAmount, + }, nil +} diff --git a/chain/actors/builtin/multisig/multisig.go b/chain/actors/builtin/multisig/state.go similarity index 64% rename from chain/actors/builtin/multisig/multisig.go rename to chain/actors/builtin/multisig/state.go index 884b6f493..89a7eedad 100644 --- a/chain/actors/builtin/multisig/multisig.go +++ b/chain/actors/builtin/multisig/state.go @@ -6,23 +6,32 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/cbor" + "github.com/ipfs/go-cid" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" ) +func init() { + builtin.RegisterActorState(builtin0.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load0(store, root) + }) + builtin.RegisterActorState(builtin2.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load2(store, root) + }) +} + func Load(store adt.Store, act *types.Actor) (State, error) { switch act.Code { case builtin0.MultisigActorCodeID: - out := state0{store: store} - err := store.Get(store.Context(), act.Head, &out) - if err != nil { - return nil, err - } - return &out, nil + return load0(store, act.Head) + case builtin2.MultisigActorCodeID: + return load2(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/multisig/v0.go b/chain/actors/builtin/multisig/state0.go similarity index 87% rename from chain/actors/builtin/multisig/v0.go rename to chain/actors/builtin/multisig/state0.go index ae0a7ac0e..c934343e7 100644 --- a/chain/actors/builtin/multisig/v0.go +++ b/chain/actors/builtin/multisig/state0.go @@ -5,15 +5,26 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/chain/actors/adt" + msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" ) var _ State = (*state0)(nil) +func load0(store adt.Store, root cid.Cid) (State, error) { + out := state0{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + type state0 struct { msig0.State store adt.Store diff --git a/chain/actors/builtin/multisig/state2.go b/chain/actors/builtin/multisig/state2.go new file mode 100644 index 000000000..a78b07d55 --- /dev/null +++ b/chain/actors/builtin/multisig/state2.go @@ -0,0 +1,70 @@ +package multisig + +import ( + "encoding/binary" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors/adt" + + msig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig" + adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" +) + +var _ State = (*state2)(nil) + +func load2(store adt.Store, root cid.Cid) (State, error) { + out := state2{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state2 struct { + msig2.State + store adt.Store +} + +func (s *state2) LockedBalance(currEpoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.State.AmountLocked(currEpoch - s.State.StartEpoch), nil +} + +func (s *state2) StartEpoch() (abi.ChainEpoch, error) { + return s.State.StartEpoch, nil +} + +func (s *state2) UnlockDuration() (abi.ChainEpoch, error) { + return s.State.UnlockDuration, nil +} + +func (s *state2) InitialBalance() (abi.TokenAmount, error) { + return s.State.InitialBalance, nil +} + +func (s *state2) Threshold() (uint64, error) { + return s.State.NumApprovalsThreshold, nil +} + +func (s *state2) Signers() ([]address.Address, error) { + return s.State.Signers, nil +} + +func (s *state2) ForEachPendingTxn(cb func(id int64, txn Transaction) error) error { + arr, err := adt2.AsMap(s.store, s.State.PendingTxns) + if err != nil { + return err + } + var out msig2.Transaction + return arr.ForEach(&out, func(key string) error { + txid, n := binary.Varint([]byte(key)) + if n <= 0 { + return xerrors.Errorf("invalid pending transaction key: %v", key) + } + return cb(txid, (Transaction)(out)) + }) +} diff --git a/chain/actors/builtin/paych/message.go b/chain/actors/builtin/paych/message.go new file mode 100644 index 000000000..23b360394 --- /dev/null +++ b/chain/actors/builtin/paych/message.go @@ -0,0 +1,28 @@ +package paych + +import ( + "fmt" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" +) + +func Message(version actors.Version, from address.Address) MessageBuilder { + switch version { + case actors.Version0: + return message0{from} + case actors.Version2: + return message2{from} + default: + panic(fmt.Sprintf("unsupported actors version: %d", version)) + } +} + +type MessageBuilder interface { + Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error) + Update(paych address.Address, voucher *SignedVoucher, secret []byte) (*types.Message, error) + Settle(paych address.Address) (*types.Message, error) + Collect(paych address.Address) (*types.Message, error) +} diff --git a/chain/actors/builtin/paych/message0.go b/chain/actors/builtin/paych/message0.go new file mode 100644 index 000000000..bfeb2731e --- /dev/null +++ b/chain/actors/builtin/paych/message0.go @@ -0,0 +1,74 @@ +package paych + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + + "github.com/filecoin-project/lotus/chain/actors" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/types" +) + +type message0 struct{ from address.Address } + +func (m message0) Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error) { + params, aerr := actors.SerializeParams(&paych0.ConstructorParams{From: m.from, To: to}) + if aerr != nil { + return nil, aerr + } + enc, aerr := actors.SerializeParams(&init0.ExecParams{ + CodeCID: builtin0.PaymentChannelActorCodeID, + ConstructorParams: params, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Value: initialAmount, + Method: builtin0.MethodsInit.Exec, + Params: enc, + }, nil +} + +func (m message0) Update(paych address.Address, sv *SignedVoucher, secret []byte) (*types.Message, error) { + params, aerr := actors.SerializeParams(&paych0.UpdateChannelStateParams{ + Sv: *sv, + Secret: secret, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin0.MethodsPaych.UpdateChannelState, + Params: params, + }, nil +} + +func (m message0) Settle(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin0.MethodsPaych.Settle, + }, nil +} + +func (m message0) Collect(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin0.MethodsPaych.Collect, + }, nil +} diff --git a/chain/actors/builtin/paych/message2.go b/chain/actors/builtin/paych/message2.go new file mode 100644 index 000000000..2cf3ef22e --- /dev/null +++ b/chain/actors/builtin/paych/message2.go @@ -0,0 +1,74 @@ +package paych + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" + paych2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/paych" + + "github.com/filecoin-project/lotus/chain/actors" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/types" +) + +type message2 struct{ from address.Address } + +func (m message2) Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error) { + params, aerr := actors.SerializeParams(&paych2.ConstructorParams{From: m.from, To: to}) + if aerr != nil { + return nil, aerr + } + enc, aerr := actors.SerializeParams(&init2.ExecParams{ + CodeCID: builtin2.PaymentChannelActorCodeID, + ConstructorParams: params, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Value: initialAmount, + Method: builtin2.MethodsInit.Exec, + Params: enc, + }, nil +} + +func (m message2) Update(paych address.Address, sv *SignedVoucher, secret []byte) (*types.Message, error) { + params, aerr := actors.SerializeParams(&paych2.UpdateChannelStateParams{ + Sv: *sv, + Secret: secret, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin2.MethodsPaych.UpdateChannelState, + Params: params, + }, nil +} + +func (m message2) Settle(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin2.MethodsPaych.Settle, + }, nil +} + +func (m message2) Collect(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin2.MethodsPaych.Collect, + }, nil +} diff --git a/chain/actors/builtin/paych/paych.go b/chain/actors/builtin/paych/state.go similarity index 62% rename from chain/actors/builtin/paych/paych.go rename to chain/actors/builtin/paych/state.go index dad54163f..20c7a74b7 100644 --- a/chain/actors/builtin/paych/paych.go +++ b/chain/actors/builtin/paych/state.go @@ -1,29 +1,42 @@ package paych import ( + "encoding/base64" + "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" big "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/cbor" + "github.com/ipfs/go-cid" + ipldcbor "github.com/ipfs/go-ipld-cbor" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" ) +func init() { + builtin.RegisterActorState(builtin0.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load0(store, root) + }) + builtin.RegisterActorState(builtin2.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load2(store, root) + }) +} + // Load returns an abstract copy of payment channel state, irregardless of actor version func Load(store adt.Store, act *types.Actor) (State, error) { switch act.Code { case builtin0.PaymentChannelActorCodeID: - out := state0{store: store} - err := store.Get(store.Context(), act.Head, &out) - if err != nil { - return nil, err - } - return &out, nil + return load0(store, act.Head) + case builtin2.PaymentChannelActorCodeID: + return load2(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -58,3 +71,18 @@ type LaneState interface { type SignedVoucher = paych0.SignedVoucher type ModVerifyParams = paych0.ModVerifyParams + +// DecodeSignedVoucher decodes base64 encoded signed voucher. +func DecodeSignedVoucher(s string) (*SignedVoucher, error) { + data, err := base64.RawURLEncoding.DecodeString(s) + if err != nil { + return nil, err + } + + var sv SignedVoucher + if err := ipldcbor.DecodeInto(data, &sv); err != nil { + return nil, err + } + + return &sv, nil +} diff --git a/chain/actors/builtin/paych/v0.go b/chain/actors/builtin/paych/state0.go similarity index 83% rename from chain/actors/builtin/paych/v0.go rename to chain/actors/builtin/paych/state0.go index c0eea1000..8e0e3434e 100644 --- a/chain/actors/builtin/paych/v0.go +++ b/chain/actors/builtin/paych/state0.go @@ -1,18 +1,31 @@ package paych import ( + "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - big "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/chain/actors/adt" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" + + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" ) var _ State = (*state0)(nil) +func load0(store adt.Store, root cid.Cid) (State, error) { + out := state0{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + type state0 struct { - paych.State + paych0.State store adt.Store lsAmt *adt0.Array } @@ -72,14 +85,14 @@ func (s *state0) ForEachLaneState(cb func(idx uint64, dl LaneState) error) error // Note: we use a map instead of an array to store laneStates because the // client sets the lane ID (the index) and potentially they could use a // very large index. - var ls paych.LaneState + var ls paych0.LaneState return lsamt.ForEach(&ls, func(i int64) error { return cb(uint64(i), &laneState0{ls}) }) } type laneState0 struct { - paych.LaneState + paych0.LaneState } func (ls *laneState0) Redeemed() (big.Int, error) { diff --git a/chain/actors/builtin/paych/state2.go b/chain/actors/builtin/paych/state2.go new file mode 100644 index 000000000..fbf4b9fde --- /dev/null +++ b/chain/actors/builtin/paych/state2.go @@ -0,0 +1,104 @@ +package paych + +import ( + "github.com/ipfs/go-cid" + + "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/chain/actors/adt" + + paych2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/paych" + adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" +) + +var _ State = (*state2)(nil) + +func load2(store adt.Store, root cid.Cid) (State, error) { + out := state2{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state2 struct { + paych2.State + store adt.Store + lsAmt *adt2.Array +} + +// Channel owner, who has funded the actor +func (s *state2) From() (address.Address, error) { + return s.State.From, nil +} + +// Recipient of payouts from channel +func (s *state2) To() (address.Address, error) { + return s.State.To, nil +} + +// Height at which the channel can be `Collected` +func (s *state2) SettlingAt() (abi.ChainEpoch, error) { + return s.State.SettlingAt, nil +} + +// Amount successfully redeemed through the payment channel, paid out on `Collect()` +func (s *state2) ToSend() (abi.TokenAmount, error) { + return s.State.ToSend, nil +} + +func (s *state2) getOrLoadLsAmt() (*adt2.Array, error) { + if s.lsAmt != nil { + return s.lsAmt, nil + } + + // Get the lane state from the chain + lsamt, err := adt2.AsArray(s.store, s.State.LaneStates) + if err != nil { + return nil, err + } + + s.lsAmt = lsamt + return lsamt, nil +} + +// Get total number of lanes +func (s *state2) LaneCount() (uint64, error) { + lsamt, err := s.getOrLoadLsAmt() + if err != nil { + return 0, err + } + return lsamt.Length(), nil +} + +// Iterate lane states +func (s *state2) ForEachLaneState(cb func(idx uint64, dl LaneState) error) error { + // Get the lane state from the chain + lsamt, err := s.getOrLoadLsAmt() + if err != nil { + return err + } + + // Note: we use a map instead of an array to store laneStates because the + // client sets the lane ID (the index) and potentially they could use a + // very large index. + var ls paych2.LaneState + return lsamt.ForEach(&ls, func(i int64) error { + return cb(uint64(i), &laneState2{ls}) + }) +} + +type laneState2 struct { + paych2.LaneState +} + +func (ls *laneState2) Redeemed() (big.Int, error) { + return ls.LaneState.Redeemed, nil +} + +func (ls *laneState2) Nonce() (uint64, error) { + return ls.LaneState.Nonce, nil +} diff --git a/chain/actors/builtin/power/power.go b/chain/actors/builtin/power/power.go index e4bb52d44..e683cfd96 100644 --- a/chain/actors/builtin/power/power.go +++ b/chain/actors/builtin/power/power.go @@ -2,28 +2,37 @@ package power import ( "github.com/filecoin-project/go-address" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/cbor" - builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" ) +func init() { + builtin.RegisterActorState(builtin0.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load0(store, root) + }) + builtin.RegisterActorState(builtin2.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load2(store, root) + }) +} + var Address = builtin0.StoragePowerActorAddr func Load(store adt.Store, act *types.Actor) (st State, err error) { switch act.Code { case builtin0.StoragePowerActorCodeID: - out := state0{store: store} - err := store.Get(store.Context(), act.Head, &out) - if err != nil { - return nil, err - } - return &out, nil + return load0(store, act.Head) + case builtin2.StoragePowerActorCodeID: + return load2(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/power/v0.go b/chain/actors/builtin/power/v0.go index f2fe96dad..e2a9cf382 100644 --- a/chain/actors/builtin/power/v0.go +++ b/chain/actors/builtin/power/v0.go @@ -3,13 +3,26 @@ package power import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" + power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/util/adt" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" ) var _ State = (*state0)(nil) +func load0(store adt.Store, root cid.Cid) (State, error) { + out := state0{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + type state0 struct { power0.State store adt.Store @@ -35,7 +48,7 @@ func (s *state0) TotalCommitted() (Claim, error) { } func (s *state0) MinerPower(addr address.Address) (Claim, bool, error) { - claims, err := adt.AsMap(s.store, s.Claims) + claims, err := adt0.AsMap(s.store, s.Claims) if err != nil { return Claim{}, false, err } @@ -63,7 +76,7 @@ func (s *state0) MinerCounts() (uint64, uint64, error) { } func (s *state0) ListAllMiners() ([]address.Address, error) { - claims, err := adt.AsMap(s.store, s.Claims) + claims, err := adt0.AsMap(s.store, s.Claims) if err != nil { return nil, err } diff --git a/chain/actors/builtin/power/v2.go b/chain/actors/builtin/power/v2.go new file mode 100644 index 000000000..6346a09b6 --- /dev/null +++ b/chain/actors/builtin/power/v2.go @@ -0,0 +1,98 @@ +package power + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" + + power2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/power" + adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" +) + +var _ State = (*state2)(nil) + +func load2(store adt.Store, root cid.Cid) (State, error) { + out := state2{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state2 struct { + power2.State + store adt.Store +} + +func (s *state2) TotalLocked() (abi.TokenAmount, error) { + return s.TotalPledgeCollateral, nil +} + +func (s *state2) TotalPower() (Claim, error) { + return Claim{ + RawBytePower: s.TotalRawBytePower, + QualityAdjPower: s.TotalQualityAdjPower, + }, nil +} + +// Committed power to the network. Includes miners below the minimum threshold. +func (s *state2) TotalCommitted() (Claim, error) { + return Claim{ + RawBytePower: s.TotalBytesCommitted, + QualityAdjPower: s.TotalQABytesCommitted, + }, nil +} + +func (s *state2) MinerPower(addr address.Address) (Claim, bool, error) { + claims, err := adt2.AsMap(s.store, s.Claims) + if err != nil { + return Claim{}, false, err + } + var claim power2.Claim + ok, err := claims.Get(abi.AddrKey(addr), &claim) + if err != nil { + return Claim{}, false, err + } + return Claim{ + RawBytePower: claim.RawBytePower, + QualityAdjPower: claim.QualityAdjPower, + }, ok, nil +} + +func (s *state2) MinerNominalPowerMeetsConsensusMinimum(a address.Address) (bool, error) { + return s.State.MinerNominalPowerMeetsConsensusMinimum(s.store, a) +} + +func (s *state2) TotalPowerSmoothed() (builtin.FilterEstimate, error) { + return builtin.FromV2FilterEstimate(s.State.ThisEpochQAPowerSmoothed), nil +} + +func (s *state2) MinerCounts() (uint64, uint64, error) { + return uint64(s.State.MinerAboveMinPowerCount), uint64(s.State.MinerCount), nil +} + +func (s *state2) ListAllMiners() ([]address.Address, error) { + claims, err := adt2.AsMap(s.store, s.Claims) + if err != nil { + return nil, err + } + + var miners []address.Address + err = claims.ForEach(nil, func(k string) error { + a, err := address.NewFromBytes([]byte(k)) + if err != nil { + return err + } + miners = append(miners, a) + return nil + }) + if err != nil { + return nil, err + } + + return miners, nil +} diff --git a/chain/actors/builtin/reward/reward.go b/chain/actors/builtin/reward/reward.go index cfa82c774..065f242e2 100644 --- a/chain/actors/builtin/reward/reward.go +++ b/chain/actors/builtin/reward/reward.go @@ -3,27 +3,35 @@ package reward import ( "github.com/filecoin-project/go-state-types/abi" reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/cbor" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" ) +func init() { + builtin.RegisterActorState(builtin0.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load0(store, root) + }) + builtin.RegisterActorState(builtin2.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load2(store, root) + }) +} + var Address = builtin0.RewardActorAddr func Load(store adt.Store, act *types.Actor) (st State, err error) { switch act.Code { case builtin0.RewardActorCodeID: - out := state0{store: store} - err := store.Get(store.Context(), act.Head, &out) - if err != nil { - return nil, err - } - return &out, nil + return load0(store, act.Head) + case builtin2.RewardActorCodeID: + return load2(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/reward/v0.go b/chain/actors/builtin/reward/v0.go index df7117b67..0efd0b482 100644 --- a/chain/actors/builtin/reward/v0.go +++ b/chain/actors/builtin/reward/v0.go @@ -2,17 +2,29 @@ package reward import ( "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/reward" - "github.com/filecoin-project/specs-actors/actors/util/adt" - "github.com/filecoin-project/specs-actors/actors/util/smoothing" + reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" + smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing" ) var _ State = (*state0)(nil) +func load0(store adt.Store, root cid.Cid) (State, error) { + out := state0{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + type state0 struct { - reward.State + reward0.State store adt.Store } @@ -54,7 +66,7 @@ func (s *state0) InitialPledgeForPower(sectorWeight abi.StoragePower, networkTot s.State.ThisEpochBaselinePower, networkTotalPledge, s.State.ThisEpochRewardSmoothed, - &smoothing.FilterEstimate{ + &smoothing0.FilterEstimate{ PositionEstimate: networkQAPower.PositionEstimate, VelocityEstimate: networkQAPower.VelocityEstimate, }, @@ -63,7 +75,7 @@ func (s *state0) InitialPledgeForPower(sectorWeight abi.StoragePower, networkTot func (s *state0) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) { return miner0.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed, - &smoothing.FilterEstimate{ + &smoothing0.FilterEstimate{ PositionEstimate: networkQAPower.PositionEstimate, VelocityEstimate: networkQAPower.VelocityEstimate, }, diff --git a/chain/actors/builtin/reward/v2.go b/chain/actors/builtin/reward/v2.go new file mode 100644 index 000000000..ec0709c39 --- /dev/null +++ b/chain/actors/builtin/reward/v2.go @@ -0,0 +1,86 @@ +package reward + +import ( + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" + + miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" + reward2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/reward" + smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing" +) + +var _ State = (*state2)(nil) + +func load2(store adt.Store, root cid.Cid) (State, error) { + out := state2{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state2 struct { + reward2.State + store adt.Store +} + +func (s *state2) ThisEpochReward() (abi.StoragePower, error) { + return s.State.ThisEpochReward, nil +} + +func (s *state2) ThisEpochRewardSmoothed() (builtin.FilterEstimate, error) { + return builtin.FilterEstimate{ + PositionEstimate: s.State.ThisEpochRewardSmoothed.PositionEstimate, + VelocityEstimate: s.State.ThisEpochRewardSmoothed.VelocityEstimate, + }, nil +} + +func (s *state2) ThisEpochBaselinePower() (abi.StoragePower, error) { + return s.State.ThisEpochBaselinePower, nil +} + +func (s *state2) TotalStoragePowerReward() (abi.TokenAmount, error) { + return s.State.TotalStoragePowerReward, nil +} + +func (s *state2) EffectiveBaselinePower() (abi.StoragePower, error) { + return s.State.EffectiveBaselinePower, nil +} + +func (s *state2) EffectiveNetworkTime() (abi.ChainEpoch, error) { + return s.State.EffectiveNetworkTime, nil +} + +func (s *state2) CumsumBaseline() (abi.StoragePower, error) { + return s.State.CumsumBaseline, nil +} + +func (s *state2) CumsumRealized() (abi.StoragePower, error) { + return s.State.CumsumBaseline, nil +} + +func (s *state2) InitialPledgeForPower(qaPower abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) { + return miner2.InitialPledgeForPower( + qaPower, + s.State.ThisEpochBaselinePower, + s.State.ThisEpochRewardSmoothed, + smoothing2.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + circSupply, + ), nil +} + +func (s *state2) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) { + return miner2.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed, + smoothing2.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + sectorWeight), nil +} diff --git a/chain/actors/builtin/verifreg/util.go b/chain/actors/builtin/verifreg/util.go new file mode 100644 index 000000000..4136c0c30 --- /dev/null +++ b/chain/actors/builtin/verifreg/util.go @@ -0,0 +1,46 @@ +package verifreg + +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/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" +) + +func getDataCap(store adt.Store, ver actors.Version, root cid.Cid, addr address.Address) (bool, abi.StoragePower, error) { + if addr.Protocol() != address.ID { + return false, big.Zero(), xerrors.Errorf("can only look up ID addresses") + } + + vh, err := adt.AsMap(store, root, ver) + if err != nil { + return false, big.Zero(), xerrors.Errorf("loading verifreg: %w", err) + } + + var dcap abi.StoragePower + if found, err := vh.Get(abi.AddrKey(addr), &dcap); err != nil { + return false, big.Zero(), xerrors.Errorf("looking up addr: %w", err) + } else if !found { + return false, big.Zero(), nil + } + + return true, dcap, nil +} + +func forEachCap(store adt.Store, ver actors.Version, root cid.Cid, cb func(addr address.Address, dcap abi.StoragePower) error) error { + vh, err := adt.AsMap(store, root, ver) + if err != nil { + return xerrors.Errorf("loading verified clients: %w", err) + } + var dcap abi.StoragePower + return vh.ForEach(&dcap, func(key string) error { + a, err := address.NewFromBytes([]byte(key)) + if err != nil { + return err + } + return cb(a, dcap) + }) +} diff --git a/chain/actors/builtin/verifreg/v0.go b/chain/actors/builtin/verifreg/v0.go index 51ed3b456..64def4706 100644 --- a/chain/actors/builtin/verifreg/v0.go +++ b/chain/actors/builtin/verifreg/v0.go @@ -3,73 +3,46 @@ package verifreg import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" - verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" - "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" + + verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" ) var _ State = (*state0)(nil) +func load0(store adt.Store, root cid.Cid) (State, error) { + out := state0{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + type state0 struct { verifreg0.State store adt.Store } -func getDataCap(store adt.Store, root cid.Cid, addr address.Address) (bool, abi.StoragePower, error) { - if addr.Protocol() != address.ID { - return false, big.Zero(), xerrors.Errorf("can only look up ID addresses") - } - - vh, err := adt0.AsMap(store, root) - if err != nil { - return false, big.Zero(), xerrors.Errorf("loading verifreg: %w", err) - } - - var dcap abi.StoragePower - if found, err := vh.Get(abi.AddrKey(addr), &dcap); err != nil { - return false, big.Zero(), xerrors.Errorf("looking up addr: %w", err) - } else if !found { - return false, big.Zero(), nil - } - - return true, dcap, nil -} - func (s *state0) RootKey() (address.Address, error) { return s.State.RootKey, nil } func (s *state0) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) { - return getDataCap(s.store, s.State.VerifiedClients, addr) + return getDataCap(s.store, actors.Version0, s.State.VerifiedClients, addr) } func (s *state0) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) { - return getDataCap(s.store, s.State.Verifiers, addr) -} - -func forEachCap(store adt.Store, root cid.Cid, cb func(addr address.Address, dcap abi.StoragePower) error) error { - vh, err := adt0.AsMap(store, root) - if err != nil { - return xerrors.Errorf("loading verified clients: %w", err) - } - var dcap abi.StoragePower - return vh.ForEach(&dcap, func(key string) error { - a, err := address.NewFromBytes([]byte(key)) - if err != nil { - return err - } - return cb(a, dcap) - }) + return getDataCap(s.store, actors.Version0, s.State.Verifiers, addr) } func (s *state0) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { - return forEachCap(s.store, s.State.Verifiers, cb) + return forEachCap(s.store, actors.Version0, s.State.Verifiers, cb) } func (s *state0) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error { - return forEachCap(s.store, s.State.VerifiedClients, cb) + return forEachCap(s.store, actors.Version0, s.State.VerifiedClients, cb) } diff --git a/chain/actors/builtin/verifreg/v2.go b/chain/actors/builtin/verifreg/v2.go new file mode 100644 index 000000000..5ee3bad05 --- /dev/null +++ b/chain/actors/builtin/verifreg/v2.go @@ -0,0 +1,48 @@ +package verifreg + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + + verifreg2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/verifreg" +) + +var _ State = (*state2)(nil) + +func load2(store adt.Store, root cid.Cid) (State, error) { + out := state2{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state2 struct { + verifreg2.State + store adt.Store +} + +func (s *state2) RootKey() (address.Address, error) { + return s.State.RootKey, nil +} + +func (s *state2) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, actors.Version2, s.State.VerifiedClients, addr) +} + +func (s *state2) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, actors.Version2, s.State.Verifiers, addr) +} + +func (s *state2) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachCap(s.store, actors.Version2, s.State.Verifiers, cb) +} + +func (s *state2) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachCap(s.store, actors.Version2, s.State.VerifiedClients, cb) +} diff --git a/chain/actors/builtin/verifreg/verifreg.go b/chain/actors/builtin/verifreg/verifreg.go index 95a60d1d9..204cdae95 100644 --- a/chain/actors/builtin/verifreg/verifreg.go +++ b/chain/actors/builtin/verifreg/verifreg.go @@ -3,26 +3,35 @@ package verifreg import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/cbor" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" ) +func init() { + builtin.RegisterActorState(builtin0.VerifiedRegistryActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load0(store, root) + }) + builtin.RegisterActorState(builtin2.VerifiedRegistryActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load2(store, root) + }) +} + var Address = builtin0.VerifiedRegistryActorAddr func Load(store adt.Store, act *types.Actor) (State, error) { switch act.Code { case builtin0.VerifiedRegistryActorCodeID: - out := state0{store: store} - err := store.Get(store.Context(), act.Head, &out) - if err != nil { - return nil, err - } - return &out, nil + return load0(store, act.Head) + case builtin2.VerifiedRegistryActorCodeID: + return load2(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/policy/policy.go b/chain/actors/policy/policy.go index b8205177e..f29da9802 100644 --- a/chain/actors/policy/policy.go +++ b/chain/actors/policy/policy.go @@ -2,10 +2,22 @@ package policy import ( "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/chain/actors" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" + miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" + verifreg2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/verifreg" +) + +const ( + ChainFinality = miner0.ChainFinality + SealRandomnessLookback = ChainFinality ) // SetSupportedProofTypes sets supported proof types, across all actor versions. @@ -17,6 +29,7 @@ func SetSupportedProofTypes(types ...abi.RegisteredSealProof) { } // Set for all miner versions. miner0.SupportedProofTypes = newTypes + miner2.SupportedProofTypes = newTypes } // AddSupportedProofTypes sets supported proof types, across all actor versions. @@ -25,6 +38,7 @@ func AddSupportedProofTypes(types ...abi.RegisteredSealProof) { for _, t := range types { // Set for all miner versions. miner0.SupportedProofTypes[t] = struct{}{} + miner2.SupportedProofTypes[t] = struct{}{} } } @@ -33,6 +47,7 @@ func AddSupportedProofTypes(types ...abi.RegisteredSealProof) { func SetPreCommitChallengeDelay(delay abi.ChainEpoch) { // Set for all miner versions. miner0.PreCommitChallengeDelay = delay + miner2.PreCommitChallengeDelay = delay } // TODO: this function shouldn't really exist. Instead, the API should expose the precommit delay. @@ -45,10 +60,50 @@ func GetPreCommitChallengeDelay() abi.ChainEpoch { // for testing. func SetConsensusMinerMinPower(p abi.StoragePower) { power0.ConsensusMinerMinPower = p + for _, policy := range builtin2.SealProofPolicies { + policy.ConsensusMinerMinPower = p + } } // SetMinVerifiedDealSize sets the minimum size of a verified deal. This should // only be used for testing. func SetMinVerifiedDealSize(size abi.StoragePower) { verifreg0.MinVerifiedDealSize = size + verifreg2.MinVerifiedDealSize = size +} + +func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) abi.ChainEpoch { + switch ver { + case actors.Version0: + return miner0.MaxSealDuration[t] + case actors.Version2: + return miner2.MaxProveCommitDuration[t] + default: + panic("unsupported actors version") + } +} + +func DealProviderCollateralBounds( + size abi.PaddedPieceSize, verified bool, + rawBytePower, qaPower, baselinePower abi.StoragePower, + circulatingFil abi.TokenAmount, nwVer network.Version, +) (min, max abi.TokenAmount) { + switch actors.VersionForNetwork(nwVer) { + case actors.Version0: + return market0.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil, nwVer) + case actors.Version2: + return market2.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil) + default: + panic("unsupported network version") + } +} + +// Sets the challenge window and scales the proving period to match (such that +// there are always 48 challenge windows in a proving period). +func SetWPoStChallengeWindow(period abi.ChainEpoch) { + miner0.WPoStChallengeWindow = period + miner0.WPoStProvingPeriod = period * abi.ChainEpoch(miner0.WPoStPeriodDeadlines) + + miner2.WPoStChallengeWindow = period + miner2.WPoStProvingPeriod = period * abi.ChainEpoch(miner2.WPoStPeriodDeadlines) } diff --git a/chain/actors/policy/policy_test.go b/chain/actors/policy/policy_test.go index be64362a2..62e7f8964 100644 --- a/chain/actors/policy/policy_test.go +++ b/chain/actors/policy/policy_test.go @@ -7,6 +7,9 @@ import ( "github.com/filecoin-project/go-state-types/abi" miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" + verifreg2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/verifreg" ) func TestSupportedProofTypes(t *testing.T) { @@ -34,3 +37,14 @@ func TestSupportedProofTypes(t *testing.T) { }, ) } + +// Tests assumptions about policies being the same between actor versions. +func TestAssumptions(t *testing.T) { + require.EqualValues(t, miner0.SupportedProofTypes, miner2.SupportedProofTypes) + require.Equal(t, miner0.PreCommitChallengeDelay, miner2.PreCommitChallengeDelay) + require.Equal(t, miner0.ChainFinality, miner2.ChainFinality) + require.Equal(t, miner0.WPoStChallengeWindow, miner2.WPoStChallengeWindow) + require.Equal(t, miner0.WPoStProvingPeriod, miner2.WPoStProvingPeriod) + require.Equal(t, miner0.WPoStPeriodDeadlines, miner2.WPoStPeriodDeadlines) + require.True(t, verifreg0.MinVerifiedDealSize.Equals(verifreg2.MinVerifiedDealSize)) +} diff --git a/chain/actors/version.go b/chain/actors/version.go new file mode 100644 index 000000000..385ff592f --- /dev/null +++ b/chain/actors/version.go @@ -0,0 +1,26 @@ +package actors + +import ( + "fmt" + + "github.com/filecoin-project/go-state-types/network" +) + +type Version int + +const ( + Version0 = 0 + Version2 = 2 +) + +// Converts a network version into an actors adt version. +func VersionForNetwork(version network.Version) Version { + switch version { + case network.Version0, network.Version1, network.Version2, network.Version3: + return Version0 + case network.Version4: + return Version2 + default: + panic(fmt.Sprintf("unsupported network version %d", version)) + } +} diff --git a/chain/gen/gen.go b/chain/gen/gen.go index d05165ab1..3ebd127f3 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -9,6 +9,7 @@ import ( "time" "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/google/uuid" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" @@ -224,7 +225,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) { }, VerifregRootKey: DefaultVerifregRootkeyActor, RemainderAccount: DefaultRemainderAccountActor, - NetworkName: "", + NetworkName: uuid.New().String(), Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()), } diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 039e284cd..bb1056e2e 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -24,7 +24,7 @@ import ( adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -115,7 +115,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, xerrors.Errorf("putting empty object: %w", err) } - state, err := state.NewStateTree(cst, builtin.Version0) + state, err := state.NewStateTree(cst, actors.Version0) if err != nil { return nil, nil, xerrors.Errorf("making new state tree: %w", err) } diff --git a/chain/messagepool/gasguess/guessgas.go b/chain/messagepool/gasguess/guessgas.go index af58db7d2..607c7824a 100644 --- a/chain/messagepool/gasguess/guessgas.go +++ b/chain/messagepool/gasguess/guessgas.go @@ -10,7 +10,9 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" ) type ActorLookup func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) @@ -27,19 +29,33 @@ type CostKey struct { } var Costs = map[CostKey]int64{ - {builtin.InitActorCodeID, 2}: 8916753, - {builtin.StorageMarketActorCodeID, 2}: 6955002, - {builtin.StorageMarketActorCodeID, 4}: 245436108, - {builtin.StorageMinerActorCodeID, 4}: 2315133, - {builtin.StorageMinerActorCodeID, 5}: 1600271356, - {builtin.StorageMinerActorCodeID, 6}: 22864493, - {builtin.StorageMinerActorCodeID, 7}: 142002419, - {builtin.StorageMinerActorCodeID, 10}: 23008274, - {builtin.StorageMinerActorCodeID, 11}: 19303178, - {builtin.StorageMinerActorCodeID, 14}: 566356835, - {builtin.StorageMinerActorCodeID, 16}: 5325185, - {builtin.StorageMinerActorCodeID, 18}: 2328637, - {builtin.StoragePowerActorCodeID, 2}: 23600956, + {builtin0.InitActorCodeID, 2}: 8916753, + {builtin0.StorageMarketActorCodeID, 2}: 6955002, + {builtin0.StorageMarketActorCodeID, 4}: 245436108, + {builtin0.StorageMinerActorCodeID, 4}: 2315133, + {builtin0.StorageMinerActorCodeID, 5}: 1600271356, + {builtin0.StorageMinerActorCodeID, 6}: 22864493, + {builtin0.StorageMinerActorCodeID, 7}: 142002419, + {builtin0.StorageMinerActorCodeID, 10}: 23008274, + {builtin0.StorageMinerActorCodeID, 11}: 19303178, + {builtin0.StorageMinerActorCodeID, 14}: 566356835, + {builtin0.StorageMinerActorCodeID, 16}: 5325185, + {builtin0.StorageMinerActorCodeID, 18}: 2328637, + {builtin0.StoragePowerActorCodeID, 2}: 23600956, + // TODO: Just reuse v0 values for now, this isn't actually used + {builtin2.InitActorCodeID, 2}: 8916753, + {builtin2.StorageMarketActorCodeID, 2}: 6955002, + {builtin2.StorageMarketActorCodeID, 4}: 245436108, + {builtin2.StorageMinerActorCodeID, 4}: 2315133, + {builtin2.StorageMinerActorCodeID, 5}: 1600271356, + {builtin2.StorageMinerActorCodeID, 6}: 22864493, + {builtin2.StorageMinerActorCodeID, 7}: 142002419, + {builtin2.StorageMinerActorCodeID, 10}: 23008274, + {builtin2.StorageMinerActorCodeID, 11}: 19303178, + {builtin2.StorageMinerActorCodeID, 14}: 566356835, + {builtin2.StorageMinerActorCodeID, 16}: 5325185, + {builtin2.StorageMinerActorCodeID, 18}: 2328637, + {builtin2.StoragePowerActorCodeID, 2}: 23600956, } func failedGuess(msg *types.SignedMessage) int64 { @@ -51,7 +67,8 @@ func failedGuess(msg *types.SignedMessage) int64 { } func GuessGasUsed(ctx context.Context, tsk types.TipSetKey, msg *types.SignedMessage, al ActorLookup) (int64, error) { - if msg.Message.Method == builtin.MethodSend { + // MethodSend is the same in all versions. + if msg.Message.Method == builtin0.MethodSend { switch msg.Message.From.Protocol() { case address.BLS: return 1298450, nil diff --git a/chain/state/statetree.go b/chain/state/statetree.go index fe932bfa1..3f9597420 100644 --- a/chain/state/statetree.go +++ b/chain/state/statetree.go @@ -13,7 +13,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors" init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" cbg "github.com/whyrusleeping/cbor-gen" @@ -26,7 +26,7 @@ var log = logging.Logger("statetree") // StateTree stores actors state by their ID. type StateTree struct { root adt.Map - version builtin.Version // TODO + version actors.Version // TODO info cid.Cid Store cbor.IpldStore @@ -120,11 +120,17 @@ func (ss *stateSnaps) deleteActor(addr address.Address) { ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true} } -func NewStateTree(cst cbor.IpldStore, version builtin.Version) (*StateTree, error) { +func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error) { var info cid.Cid switch version { - case builtin.Version0: + case actors.Version0: // info is undefined + case actors.Version2: + var err error + info, err = cst.Put(context.TODO(), new(types.StateInfo)) + if err != nil { + return nil, err + } default: return nil, xerrors.Errorf("unsupported state tree version: %d", version) } @@ -148,30 +154,28 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) { if err := cst.Get(context.TODO(), c, &root); err != nil { // We failed to decode as the new version, must be an old version. root.Actors = c - root.Version = builtin.Version0 - } - - // If that fails, load as an old-style state-tree (direct hampt, version 0. - nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, builtin.Version(root.Version)) - if err != nil { - log.Errorf("loading hamt node %s failed: %s", c, err) - return nil, err + root.Version = actors.Version0 } switch root.Version { - case builtin.Version0: - // supported + case actors.Version0, actors.Version2: + // Load the actual state-tree HAMT. + nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, actors.Version(root.Version)) + if err != nil { + log.Errorf("loading hamt node %s failed: %s", c, err) + return nil, err + } + + return &StateTree{ + root: nd, + info: root.Info, + version: actors.Version(root.Version), + Store: cst, + snaps: newStateSnaps(), + }, nil default: return nil, xerrors.Errorf("unsupported state tree version: %d", root.Version) } - - return &StateTree{ - root: nd, - info: root.Info, - version: builtin.Version(root.Version), - Store: cst, - snaps: newStateSnaps(), - }, nil } func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error { @@ -305,7 +309,7 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) { return cid.Undef, xerrors.Errorf("failed to flush state-tree hamt: %w", err) } // If we're version 0, return a raw tree. - if st.version == builtin.Version0 { + if st.version == actors.Version0 { return root, nil } // Otherwise, return a versioned tree. @@ -396,7 +400,7 @@ func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error } // Version returns the version of the StateTree data structure in use. -func (st *StateTree) Version() builtin.Version { +func (st *StateTree) Version() actors.Version { return st.version } diff --git a/chain/state/statetree_test.go b/chain/state/statetree_test.go index 79ab20606..3b08a4b53 100644 --- a/chain/state/statetree_test.go +++ b/chain/state/statetree_test.go @@ -9,16 +9,17 @@ import ( cbor "github.com/ipfs/go-ipld-cbor" address "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/lotus/build" - builtin2 "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" ) func BenchmarkStateTreeSet(b *testing.B) { cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) + st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion)) if err != nil { b.Fatal(err) } @@ -45,7 +46,7 @@ func BenchmarkStateTreeSet(b *testing.B) { func BenchmarkStateTreeSetFlush(b *testing.B) { cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) + st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion)) if err != nil { b.Fatal(err) } @@ -75,7 +76,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) { func BenchmarkStateTree10kGetActor(b *testing.B) { cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) + st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion)) if err != nil { b.Fatal(err) } @@ -117,7 +118,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) { func TestSetCache(t *testing.T) { cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) + st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion)) if err != nil { t.Fatal(err) } @@ -154,7 +155,7 @@ func TestSetCache(t *testing.T) { func TestSnapshots(t *testing.T) { ctx := context.Background() cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) + st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion)) if err != nil { t.Fatal(err) } @@ -237,7 +238,8 @@ func assertNotHas(t *testing.T, st *StateTree, addr address.Address) { func TestStateTreeConsistency(t *testing.T) { cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) + // TODO: ActorUpgrade: this test tests pre actors v2 + st, err := NewStateTree(cst, actors.VersionForNetwork(network.Version3)) if err != nil { t.Fatal(err) } diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index f4dfc7115..15cbac53e 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" "github.com/ipfs/go-cid" "go.opencensus.io/trace" @@ -18,14 +17,26 @@ import ( "github.com/filecoin-project/lotus/chain/vm" ) -func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate cid.Cid, r vm.Rand, bheight abi.ChainEpoch) (*api.InvocResult, error) { - ctx, span := trace.StartSpan(ctx, "statemanager.CallRaw") +func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) { + ctx, span := trace.StartSpan(ctx, "statemanager.Call") defer span.End() + if ts == nil { + ts = sm.cs.GetHeaviestTipSet() + } + + bstate := ts.ParentState() + bheight := ts.Height() + + bstate, err := sm.handleStateForks(ctx, bstate, bheight-1, nil, ts) + if err != nil { + return nil, fmt.Errorf("failed to handle fork: %w", err) + } + vmopt := &vm.VMOpts{ StateBase: bstate, Epoch: bheight, - Rand: r, + Rand: store.NewChainRand(sm.cs, ts.Cids()), Bstore: sm.cs.Blockstore(), Syscalls: sm.cs.VMSys(), CircSupplyCalc: sm.GetCirculatingSupply, @@ -89,18 +100,6 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate } -func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) { - if ts == nil { - ts = sm.cs.GetHeaviestTipSet() - } - - state := ts.ParentState() - - r := store.NewChainRand(sm.cs, ts.Cids()) - - return sm.CallRaw(ctx, msg, state, r, ts.Height()) -} - func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, priorMsgs []types.ChainMsg, ts *types.TipSet) (*api.InvocResult, error) { ctx, span := trace.StartSpan(ctx, "statemanager.CallWithGas") defer span.End() @@ -114,6 +113,11 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri return nil, xerrors.Errorf("computing tipset state: %w", err) } + state, err = sm.handleStateForks(ctx, state, ts.Height(), nil, ts) + if err != nil { + return nil, fmt.Errorf("failed to handle fork: %w", err) + } + r := store.NewChainRand(sm.cs, ts.Cids()) if span.IsRecordingEvents() { diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index 252b731d7..d5d0dbf7e 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -6,43 +6,108 @@ import ( "encoding/binary" "math" - multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" - - "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" - - "github.com/filecoin-project/lotus/chain/state" - - "github.com/filecoin-project/specs-actors/actors/migration/nv3" - - "github.com/ipfs/go-cid" - "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/network" + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + "golang.org/x/xerrors" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" - init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/specs-actors/actors/migration/nv3" + m2 "github.com/filecoin-project/specs-actors/v2/actors/migration" + states2 "github.com/filecoin-project/specs-actors/v2/actors/states" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" + "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" - cbor "github.com/ipfs/go-ipld-cbor" - "golang.org/x/xerrors" ) -var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, ExecCallback, cid.Cid, *types.TipSet) (cid.Cid, error){ - build.UpgradeBreezeHeight: UpgradeFaucetBurnRecovery, - build.UpgradeIgnitionHeight: UpgradeIgnition, - build.UpgradeLiftoffHeight: UpgradeLiftoff, +type UpgradeFunc func(context.Context, *StateManager, ExecCallback, cid.Cid, *types.TipSet) (cid.Cid, error) + +type Upgrade struct { + Height abi.ChainEpoch + Network network.Version + Migration UpgradeFunc +} + +type UpgradeSchedule []Upgrade + +func DefaultUpgradeSchedule() UpgradeSchedule { + var us UpgradeSchedule + + for _, u := range []Upgrade{{ + Height: build.UpgradeBreezeHeight, + Network: network.Version1, + Migration: UpgradeFaucetBurnRecovery, + }, { + Height: build.UpgradeSmokeHeight, + Network: network.Version2, + Migration: nil, + }, { + Height: build.UpgradeIgnitionHeight, + Network: network.Version3, + Migration: UpgradeIgnition, + }, { + Height: build.UpgradeActorsV2Height, + Network: network.Version4, + Migration: UpgradeActorsV2, + }, { + Height: build.UpgradeLiftoffHeight, + Network: network.Version4, + Migration: UpgradeLiftoff, + }} { + if u.Height < 0 { + // upgrade disabled + continue + } + us = append(us, u) + } + return us +} + +func (us UpgradeSchedule) Validate() error { + // Make sure we're not trying to upgrade to version 0. + for _, u := range us { + if u.Network <= 0 { + return xerrors.Errorf("cannot upgrade to version <= 0: %d", u.Network) + } + } + + // Make sure all the upgrades make sense. + for i := 1; i < len(us); i++ { + prev := &us[i-1] + curr := &us[i] + if !(prev.Network <= curr.Network) { + return xerrors.Errorf("cannot downgrade from version %d to version %d", prev.Network, curr.Network) + } + // Make sure the heights make sense. + if prev.Height < 0 { + // Previous upgrade was disabled. + continue + } + if !(prev.Height < curr.Height) { + return xerrors.Errorf("upgrade heights must be strictly increasing: upgrade %d was at height %d, followed by upgrade %d at height %d", i-1, prev.Height, i, curr.Height) + } + } + return nil } func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, height abi.ChainEpoch, cb ExecCallback, ts *types.TipSet) (cid.Cid, error) { retCid := root var err error - f, ok := ForksAtHeight[height] + f, ok := sm.stateMigrations[height] if ok { retCid, err = f(ctx, sm, cb, root, ts) if err != nil { @@ -370,7 +435,13 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) { store := sm.cs.Store(ctx) - nst, err := nv3.MigrateStateTree(ctx, store, root, build.UpgradeIgnitionHeight) + epoch := ts.Height() - 1 + + if build.UpgradeLiftoffHeight <= epoch { + return cid.Undef, xerrors.Errorf("liftoff height must be beyond ignition height") + } + + nst, err := nv3.MigrateStateTree(ctx, store, root, epoch) if err != nil { return cid.Undef, xerrors.Errorf("migrating actors state: %w", err) } @@ -395,7 +466,7 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo return cid.Undef, xerrors.Errorf("second split address: %w", err) } - err = resetGenesisMsigs(ctx, sm, store, tree) + err = resetGenesisMsigs(ctx, sm, store, tree, build.UpgradeLiftoffHeight) if err != nil { return cid.Undef, xerrors.Errorf("resetting genesis msig start epochs: %w", err) } @@ -410,7 +481,7 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo return cid.Undef, xerrors.Errorf("splitting second msig: %w", err) } - err = nv3.CheckStateTree(ctx, store, nst, build.UpgradeIgnitionHeight, builtin0.TotalFilecoin) + err = nv3.CheckStateTree(ctx, store, nst, epoch, builtin0.TotalFilecoin) if err != nil { return cid.Undef, xerrors.Errorf("sanity check after ignition upgrade failed: %w", err) } @@ -418,6 +489,58 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo return tree.Flush(ctx) } +func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) { + store := sm.cs.Store(ctx) + + epoch := ts.Height() - 1 + + info, err := store.Put(ctx, new(types.StateInfo)) + if err != nil { + return cid.Undef, xerrors.Errorf("failed to create new state info for actors v2: %w", err) + } + + newHamtRoot, err := m2.MigrateStateTree(ctx, store, root, epoch, m2.DefaultConfig()) + if err != nil { + return cid.Undef, xerrors.Errorf("upgrading to actors v2: %w", err) + } + + newStateTree, err := states2.LoadTree(store, newHamtRoot) + if err != nil { + return cid.Undef, xerrors.Errorf("failed to load new state tree: %w", err) + } + + // Check all state-tree invariants. + if msgs, err := states2.CheckStateInvariants(newStateTree, types.TotalFilecoinInt); err != nil { + return cid.Undef, xerrors.Errorf("failed to check new state tree: %w", err) + } else if !msgs.IsEmpty() { + // This error is going to be really nasty. + return cid.Undef, xerrors.Errorf("network upgrade failed: %v", msgs.Messages()) + } + + newRoot, err := store.Put(ctx, &types.StateRoot{ + // TODO: ActorUpgrade: should be state-tree specific, not just the actors version. + Version: actors.Version2, + Actors: newHamtRoot, + Info: info, + }) + if err != nil { + return cid.Undef, xerrors.Errorf("failed to persist new state root: %w", err) + } + + // perform some basic sanity checks to make sure everything still works. + if newSm, err := state.LoadStateTree(store, newRoot); err != nil { + return cid.Undef, xerrors.Errorf("state tree sanity load failed: %w", err) + } else if newRoot2, err := newSm.Flush(ctx); err != nil { + return cid.Undef, xerrors.Errorf("state tree sanity flush failed: %w", err) + } else if newRoot2 != newRoot { + return cid.Undef, xerrors.Errorf("state-root mismatch: %s != %s", newRoot, newRoot2) + } else if _, err := newSm.GetActor(builtin0.InitActorAddr); err != nil { + return cid.Undef, xerrors.Errorf("failed to load init actor after upgrade: %w", err) + } + + return newRoot, nil +} + func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) { tree, err := sm.StateTree(root) if err != nil { @@ -432,20 +555,22 @@ func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root return tree.Flush(ctx) } -func setNetworkName(ctx context.Context, store adt0.Store, tree *state.StateTree, name string) error { +func setNetworkName(ctx context.Context, store adt.Store, tree *state.StateTree, name string) error { ia, err := tree.GetActor(builtin0.InitActorAddr) if err != nil { return xerrors.Errorf("getting init actor: %w", err) } - var initState init0.State - if err := store.Get(ctx, ia.Head, &initState); err != nil { + initState, err := init_.Load(store, ia) + if err != nil { return xerrors.Errorf("reading init state: %w", err) } - initState.NetworkName = name + if err := initState.SetNetworkName(name); err != nil { + return xerrors.Errorf("setting network name: %w", err) + } - ia.Head, err = store.Put(ctx, &initState) + ia.Head, err = store.Put(ctx, initState) if err != nil { return xerrors.Errorf("writing new init state: %w", err) } @@ -574,7 +699,7 @@ func makeKeyAddr(splitAddr address.Address, count uint64) (address.Address, erro return addr, nil } -func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store, tree *state.StateTree) error { +func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store, tree *state.StateTree, startEpoch abi.ChainEpoch) error { gb, err := sm.cs.GetGenesis() if err != nil { return xerrors.Errorf("getting genesis block: %w", err) @@ -603,7 +728,7 @@ func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store, return xerrors.Errorf("reading multisig state: %w", err) } - currState.StartEpoch = build.UpgradeLiftoffHeight + currState.StartEpoch = startEpoch currActor.Head, err = store.Put(ctx, &currState) if err != nil { diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index a3423ccdd..bb03f13b9 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -8,6 +8,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/specs-actors/actors/builtin" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" "github.com/filecoin-project/specs-actors/actors/runtime" @@ -18,7 +19,6 @@ import ( lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init" "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/gen" - "github.com/filecoin-project/lotus/chain/stmgr" . "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" @@ -26,7 +26,7 @@ import ( _ "github.com/filecoin-project/lotus/lib/sigs/secp" "github.com/ipfs/go-cid" - cbor "github.com/ipfs/go-ipld-cbor" + ipldcbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log" cbg "github.com/whyrusleeping/cbor-gen" ) @@ -42,6 +42,10 @@ const testForkHeight = 40 type testActor struct { } +// must use existing actor that an account is allowed to exec. +func (testActor) Code() cid.Cid { return builtin.PaymentChannelActorCodeID } +func (testActor) State() cbor.Er { return new(testActorState) } + type testActorState struct { HasUpgraded uint64 } @@ -62,7 +66,7 @@ func (tas *testActorState) UnmarshalCBOR(r io.Reader) error { return nil } -func (ta *testActor) Exports() []interface{} { +func (ta testActor) Exports() []interface{} { return []interface{}{ 1: ta.Constructor, 2: ta.TestMethod, @@ -105,51 +109,57 @@ func TestForkHeightTriggers(t *testing.T) { t.Fatal(err) } - sm := NewStateManager(cg.ChainStore()) - - inv := vm.NewInvoker() - // predicting the address here... may break if other assumptions change taddr, err := address.NewIDAddress(1002) if err != nil { t.Fatal(err) } - stmgr.ForksAtHeight[testForkHeight] = func(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) { - cst := cbor.NewCborStore(sm.ChainStore().Blockstore()) + sm, err := NewStateManagerWithUpgradeSchedule( + cg.ChainStore(), UpgradeSchedule{{ + Network: 1, + Height: testForkHeight, + Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback, + root cid.Cid, ts *types.TipSet) (cid.Cid, error) { + cst := ipldcbor.NewCborStore(sm.ChainStore().Blockstore()) - st, err := sm.StateTree(root) - if err != nil { - return cid.Undef, xerrors.Errorf("getting state tree: %w", err) - } + st, err := sm.StateTree(root) + if err != nil { + return cid.Undef, xerrors.Errorf("getting state tree: %w", err) + } - act, err := st.GetActor(taddr) - if err != nil { - return cid.Undef, err - } + act, err := st.GetActor(taddr) + if err != nil { + return cid.Undef, err + } - var tas testActorState - if err := cst.Get(ctx, act.Head, &tas); err != nil { - return cid.Undef, xerrors.Errorf("in fork handler, failed to run get: %w", err) - } + var tas testActorState + if err := cst.Get(ctx, act.Head, &tas); err != nil { + return cid.Undef, xerrors.Errorf("in fork handler, failed to run get: %w", err) + } - tas.HasUpgraded = 55 + tas.HasUpgraded = 55 - ns, err := cst.Put(ctx, &tas) - if err != nil { - return cid.Undef, err - } + ns, err := cst.Put(ctx, &tas) + if err != nil { + return cid.Undef, err + } - act.Head = ns + act.Head = ns - if err := st.SetActor(taddr, act); err != nil { - return cid.Undef, err - } + if err := st.SetActor(taddr, act); err != nil { + return cid.Undef, err + } - return st.Flush(ctx) + return st.Flush(ctx) + }}}) + if err != nil { + t.Fatal(err) } - inv.Register(builtin.PaymentChannelActorCodeID, &testActor{}, &testActorState{}) + inv := vm.NewActorRegistry() + inv.Register(nil, testActor{}) + sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) { nvm, err := vm.NewVM(ctx, vmopt) if err != nil { @@ -163,7 +173,7 @@ func TestForkHeightTriggers(t *testing.T) { var msgs []*types.SignedMessage - enc, err := actors.SerializeParams(&init_.ExecParams{CodeCID: builtin.PaymentChannelActorCodeID}) + enc, err := actors.SerializeParams(&init_.ExecParams{CodeCID: (testActor{}).Code()}) if err != nil { t.Fatal(err) } diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 90e43ebbc..e371992e8 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -5,6 +5,8 @@ import ( "fmt" "sync" + "github.com/filecoin-project/lotus/chain/actors/builtin" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" @@ -24,7 +26,6 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" - "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" "github.com/filecoin-project/lotus/chain/actors/builtin/paych" @@ -38,9 +39,21 @@ import ( var log = logging.Logger("statemgr") +type versionSpec struct { + networkVersion network.Version + atOrBelow abi.ChainEpoch +} + type StateManager struct { cs *store.ChainStore + // Determines the network version at any given epoch. + networkVersions []versionSpec + latestVersion network.Version + + // Maps chain epochs to upgrade functions. + stateMigrations map[abi.ChainEpoch]UpgradeFunc + stCache map[string][]cid.Cid compWait map[string]chan struct{} stlk sync.Mutex @@ -51,12 +64,49 @@ type StateManager struct { } func NewStateManager(cs *store.ChainStore) *StateManager { - return &StateManager{ - newVM: vm.NewVM, - cs: cs, - stCache: make(map[string][]cid.Cid), - compWait: make(map[string]chan struct{}), + sm, err := NewStateManagerWithUpgradeSchedule(cs, DefaultUpgradeSchedule()) + if err != nil { + panic(fmt.Sprintf("default upgrade schedule is invalid: %s", err)) } + return sm +} + +func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule) (*StateManager, error) { + // If we have upgrades, make sure they're in-order and make sense. + if err := us.Validate(); err != nil { + return nil, err + } + + stateMigrations := make(map[abi.ChainEpoch]UpgradeFunc, len(us)) + var networkVersions []versionSpec + lastVersion := network.Version0 + if len(us) > 0 { + // If we have any upgrades, process them and create a version + // schedule. + for _, upgrade := range us { + if upgrade.Migration != nil { + stateMigrations[upgrade.Height] = upgrade.Migration + } + networkVersions = append(networkVersions, versionSpec{ + networkVersion: lastVersion, + atOrBelow: upgrade.Height, + }) + lastVersion = upgrade.Network + } + } else { + // Otherwise, go directly to the latest version. + lastVersion = build.NewestNetworkVersion + } + + return &StateManager{ + networkVersions: networkVersions, + latestVersion: lastVersion, + stateMigrations: stateMigrations, + newVM: vm.NewVM, + cs: cs, + stCache: make(map[string][]cid.Cid), + compWait: make(map[string]chan struct{}), + }, nil } func cidsToKey(cids []cid.Cid) string { @@ -279,7 +329,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp sysAct, actErr := vmi.StateTree().GetActor(builtin0.SystemActorAddr) if actErr != nil { - return cid.Undef, cid.Undef, xerrors.Errorf("failed to get system actor: %w", err) + return cid.Undef, cid.Undef, xerrors.Errorf("failed to get system actor: %w", actErr) } rwMsg := &types.Message{ @@ -295,7 +345,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp } ret, actErr := vmi.ApplyImplicitMessage(ctx, rwMsg) if actErr != nil { - return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, err) + return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, actErr) } if cb != nil { if err := cb(rwMsg.Cid(), rwMsg, ret); err != nil { @@ -313,7 +363,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp } // XXX: Is the height correct? Or should it be epoch-1? - rectarr, err := adt.NewArray(sm.cs.Store(ctx), builtin.VersionForNetwork(sm.GetNtwkVersion(ctx, epoch))) + rectarr, err := adt.NewArray(sm.cs.Store(ctx), actors.VersionForNetwork(sm.GetNtwkVersion(ctx, epoch))) if err != nil { return cid.Undef, cid.Undef, xerrors.Errorf("failed to create receipts amt: %w", err) } @@ -859,7 +909,7 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error { totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount) err = sTree.ForEach(func(kaddr address.Address, act *types.Actor) error { - if act.IsMultisigActor() { + if builtin.IsMultisigActor(act.Code) { s, err := multisig.Load(sm.cs.Store(ctx), act) if err != nil { return err @@ -891,7 +941,7 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error { totalsByEpoch[ud] = ib } - } else if act.IsAccountActor() { + } else if builtin.IsAccountActor(act.Code) { // should exclude burnt funds actor and "remainder account actor" // should only ever be "faucet" accounts in testnets if kaddr == builtin0.BurntFundsActorAddr { @@ -1258,25 +1308,14 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha } func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version { - // TODO: move hard fork epoch checks to a schedule defined in build/ - - if build.UseNewestNetwork() { - return build.NewestNetworkVersion + // The epochs here are the _last_ epoch for every version, or -1 if the + // version is disabled. + for _, spec := range sm.networkVersions { + if height <= spec.atOrBelow { + return spec.networkVersion + } } - - if height <= build.UpgradeBreezeHeight { - return network.Version0 - } - - if height <= build.UpgradeSmokeHeight { - return network.Version1 - } - - if height <= build.UpgradeIgnitionHeight { - return network.Version2 - } - - return build.NewestNetworkVersion + return sm.latestVersion } func (sm *StateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) { diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index bac5a31f5..98f6bc5ac 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -17,19 +17,12 @@ import ( "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/rt" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" - account0 "github.com/filecoin-project/specs-actors/actors/builtin/account" - cron0 "github.com/filecoin-project/specs-actors/actors/builtin/cron" - init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" - market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" - miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" - msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" - paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" - power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" - reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" - verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported" proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof" + exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -534,42 +527,23 @@ type MethodMeta struct { var MethodsMap = map[cid.Cid]map[abi.MethodNum]MethodMeta{} func init() { - cidToMethods := map[cid.Cid][2]interface{}{ - // builtin.SystemActorCodeID: {builtin.MethodsSystem, system.Actor{} }- apparently it doesn't have methods - builtin0.InitActorCodeID: {builtin0.MethodsInit, init0.Actor{}}, - builtin0.CronActorCodeID: {builtin0.MethodsCron, cron0.Actor{}}, - builtin0.AccountActorCodeID: {builtin0.MethodsAccount, account0.Actor{}}, - builtin0.StoragePowerActorCodeID: {builtin0.MethodsPower, power0.Actor{}}, - builtin0.StorageMinerActorCodeID: {builtin0.MethodsMiner, miner0.Actor{}}, - builtin0.StorageMarketActorCodeID: {builtin0.MethodsMarket, market0.Actor{}}, - builtin0.PaymentChannelActorCodeID: {builtin0.MethodsPaych, paych0.Actor{}}, - builtin0.MultisigActorCodeID: {builtin0.MethodsMultisig, msig0.Actor{}}, - builtin0.RewardActorCodeID: {builtin0.MethodsReward, reward0.Actor{}}, - builtin0.VerifiedRegistryActorCodeID: {builtin0.MethodsVerifiedRegistry, verifreg0.Actor{}}, - } + // TODO: combine with the runtime actor registry. + var actors []rt.VMActor + actors = append(actors, exported0.BuiltinActors()...) + actors = append(actors, exported2.BuiltinActors()...) - for c, m := range cidToMethods { - exports := m[1].(vm.Invokee).Exports() + for _, actor := range actors { + exports := actor.Exports() methods := make(map[abi.MethodNum]MethodMeta, len(exports)) // Explicitly add send, it's special. + // Note that builtin2.MethodSend = builtin0.MethodSend = 0. methods[builtin0.MethodSend] = MethodMeta{ Name: "Send", Params: reflect.TypeOf(new(abi.EmptyValue)), Ret: reflect.TypeOf(new(abi.EmptyValue)), } - // Learn method names from the builtin.Methods* structs. - rv := reflect.ValueOf(m[0]) - rt := rv.Type() - nf := rt.NumField() - methodToName := make([]string, len(exports)) - for i := 0; i < nf; i++ { - name := rt.Field(i).Name - number := rv.Field(i).Interface().(abi.MethodNum) - methodToName[number] = name - } - // Iterate over exported methods. Some of these _may_ be nil and // must be skipped. for number, export := range exports { @@ -580,22 +554,19 @@ func init() { ev := reflect.ValueOf(export) et := ev.Type() - // Make sure the method name is correct. - // This is just a nice sanity check. + // Extract the method names using reflection. These + // method names always match the field names in the + // `builtin.Method*` structs (tested in the specs-actors + // tests). fnName := runtime.FuncForPC(ev.Pointer()).Name() fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm") - mName := methodToName[number] - if mName != fnName { - panic(fmt.Sprintf( - "actor method name is %s but exported method name is %s", - fnName, mName, - )) - } switch abi.MethodNum(number) { case builtin0.MethodSend: + // Note that builtin2.MethodSend = builtin0.MethodSend = 0. panic("method 0 is reserved for Send") case builtin0.MethodConstructor: + // Note that builtin2.MethodConstructor = builtin0.MethodConstructor = 1. if fnName != "Constructor" { panic("method 1 is reserved for Constructor") } @@ -607,7 +578,7 @@ func init() { Ret: et.Out(0), } } - MethodsMap[c] = methods + MethodsMap[actor.Code()] = methods } } diff --git a/chain/store/basefee.go b/chain/store/basefee.go index 45785240e..33367abcc 100644 --- a/chain/store/basefee.go +++ b/chain/store/basefee.go @@ -46,7 +46,7 @@ func ComputeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int } func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi.TokenAmount, error) { - if ts.Height() > build.UpgradeBreezeHeight && ts.Height() < build.UpgradeBreezeHeight+build.BreezeGasTampingDuration { + if build.UpgradeBreezeHeight >= 0 && ts.Height() > build.UpgradeBreezeHeight && ts.Height() < build.UpgradeBreezeHeight+build.BreezeGasTampingDuration { return abi.NewTokenAmount(100), nil } diff --git a/chain/store/basefee_test.go b/chain/store/basefee_test.go index b4757f70e..b3d414cf5 100644 --- a/chain/store/basefee_test.go +++ b/chain/store/basefee_test.go @@ -11,24 +11,27 @@ import ( func TestBaseFee(t *testing.T) { tests := []struct { - basefee uint64 - limitUsed int64 - noOfBlocks int - output uint64 + basefee uint64 + limitUsed int64 + noOfBlocks int + preSmoke, postSmoke uint64 }{ - {100e6, 0, 1, 87.5e6}, - {100e6, 0, 5, 87.5e6}, - {100e6, build.BlockGasTarget, 1, 103.125e6}, - {100e6, build.BlockGasTarget * 2, 2, 103.125e6}, - {100e6, build.BlockGasLimit * 2, 2, 112.5e6}, - {100e6, build.BlockGasLimit * 1.5, 2, 110937500}, + {100e6, 0, 1, 87.5e6, 87.5e6}, + {100e6, 0, 5, 87.5e6, 87.5e6}, + {100e6, build.BlockGasTarget, 1, 103.125e6, 100e6}, + {100e6, build.BlockGasTarget * 2, 2, 103.125e6, 100e6}, + {100e6, build.BlockGasLimit * 2, 2, 112.5e6, 112.5e6}, + {100e6, build.BlockGasLimit * 1.5, 2, 110937500, 106.250e6}, } for _, test := range tests { test := test t.Run(fmt.Sprintf("%v", test), func(t *testing.T) { - output := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, 0) - assert.Equal(t, fmt.Sprintf("%d", test.output), output.String()) + preSmoke := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, build.UpgradeSmokeHeight-1) + assert.Equal(t, fmt.Sprintf("%d", test.preSmoke), preSmoke.String()) + + postSmoke := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, build.UpgradeSmokeHeight+1) + assert.Equal(t, fmt.Sprintf("%d", test.postSmoke), postSmoke.String()) }) } } diff --git a/chain/store/store.go b/chain/store/store.go index 0c99b9d43..aac28e5d3 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -17,11 +17,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/util/adt" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/journal" bstore "github.com/filecoin-project/lotus/lib/blockstore" @@ -757,7 +759,8 @@ func (cs *ChainStore) GetSignedMessage(c cid.Cid) (*types.SignedMessage, error) func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) { ctx := context.TODO() - a, err := adt.AsArray(cs.Store(ctx), root) + // block headers use adt0, for now. + a, err := adt0.AsArray(cs.Store(ctx), root) if err != nil { return nil, xerrors.Errorf("amt load: %w", err) } @@ -950,7 +953,8 @@ func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message, func (cs *ChainStore) GetParentReceipt(b *types.BlockHeader, i int) (*types.MessageReceipt, error) { ctx := context.TODO() - a, err := adt.AsArray(cs.Store(ctx), b.ParentMessageReceipts) + // block headers use adt0, for now. + a, err := adt0.AsArray(cs.Store(ctx), b.ParentMessageReceipts) if err != nil { return nil, xerrors.Errorf("amt load: %w", err) } diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index 0c72b4d80..53bc3d68e 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -10,7 +10,6 @@ import ( "golang.org/x/xerrors" address "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/util/adt" lru "github.com/hashicorp/golang-lru" blocks "github.com/ipfs/go-block-format" bserv "github.com/ipfs/go-blockservice" @@ -24,6 +23,8 @@ import ( "go.opencensus.io/stats" "go.opencensus.io/tag" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" @@ -384,9 +385,10 @@ func (bv *BlockValidator) isChainNearSynced() bool { func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error { // TODO there has to be a simpler way to do this without the blockstore dance - store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewTemporary())) - bmArr := adt.MakeEmptyArray(store) - smArr := adt.MakeEmptyArray(store) + // block headers use adt0 + store := adt0.WrapStore(ctx, cbor.NewCborStore(blockstore.NewTemporary())) + bmArr := adt0.MakeEmptyArray(store) + smArr := adt0.MakeEmptyArray(store) for i, m := range msg.BlsMessages { c := cbg.CborCid(m) diff --git a/chain/sync.go b/chain/sync.go index b2e3bb7f1..46d3934b1 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -11,6 +11,8 @@ import ( "sync" "time" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/specs-actors/actors/runtime/proof" @@ -33,9 +35,10 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/util/adt" blst "github.com/supranational/blst/bindings/go" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/power" @@ -455,9 +458,10 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types // computeMsgMeta computes the root CID of the combined arrays of message CIDs // of both types (BLS and Secpk). func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cid.Cid) (cid.Cid, error) { - store := adt.WrapStore(context.TODO(), bs) - bmArr := adt.MakeEmptyArray(store) - smArr := adt.MakeEmptyArray(store) + // block headers use adt0 + store := adt0.WrapStore(context.TODO(), bs) + bmArr := adt0.MakeEmptyArray(store) + smArr := adt0.MakeEmptyArray(store) for i, m := range bmsgCids { c := cbg.CborCid(m) @@ -1087,7 +1091,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock return xerrors.Errorf("failed to get actor: %w", err) } - if !act.IsAccountActor() { + if !builtin.IsAccountActor(act.Code) { return xerrors.New("Sender must be an account actor") } nonces[m.From] = act.Nonce @@ -1101,9 +1105,9 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock return nil } - store := adt.WrapStore(ctx, cst) + store := adt0.WrapStore(ctx, cst) - bmArr := adt.MakeEmptyArray(store) + bmArr := adt0.MakeEmptyArray(store) for i, m := range b.BlsMessages { if err := checkMsg(m); err != nil { return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err) @@ -1115,7 +1119,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock } } - smArr := adt.MakeEmptyArray(store) + smArr := adt0.MakeEmptyArray(store) for i, m := range b.SecpkMessages { if err := checkMsg(m); err != nil { return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err) diff --git a/chain/types/actor.go b/chain/types/actor.go index eb8e05c49..a9974a01f 100644 --- a/chain/types/actor.go +++ b/chain/types/actor.go @@ -4,8 +4,6 @@ import ( "errors" "github.com/ipfs/go-cid" - - builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" ) var ErrActorNotFound = errors.New("actor not found") @@ -17,19 +15,3 @@ type Actor struct { Nonce uint64 Balance BigInt } - -func (a *Actor) IsAccountActor() bool { - return a.Code == builtin0.AccountActorCodeID -} - -func (a *Actor) IsStorageMinerActor() bool { - return a.Code == builtin0.StorageMinerActorCodeID -} - -func (a *Actor) IsMultisigActor() bool { - return a.Code == builtin0.MultisigActorCodeID -} - -func (a *Actor) IsPaymentChannelActor() bool { - return a.Code == builtin0.PaymentChannelActorCodeID -} diff --git a/chain/types/voucher.go b/chain/types/voucher.go deleted file mode 100644 index 687109c33..000000000 --- a/chain/types/voucher.go +++ /dev/null @@ -1,22 +0,0 @@ -package types - -import ( - "encoding/base64" - - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - cbor "github.com/ipfs/go-ipld-cbor" -) - -func DecodeSignedVoucher(s string) (*paych.SignedVoucher, error) { - data, err := base64.RawURLEncoding.DecodeString(s) - if err != nil { - return nil, err - } - - var sv paych.SignedVoucher - if err := cbor.DecodeInto(data, &sv); err != nil { - return nil, err - } - - return &sv, nil -} diff --git a/chain/vectors/gen/main.go b/chain/vectors/gen/main.go index 2b1c6f340..51d907648 100644 --- a/chain/vectors/gen/main.go +++ b/chain/vectors/gen/main.go @@ -6,28 +6,25 @@ import ( "math/rand" "os" - power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/go-address" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/mock" "github.com/filecoin-project/lotus/chain/vectors" "github.com/filecoin-project/lotus/chain/wallet" - verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" ) func init() { - verifreg0.MinVerifiedDealSize = big.NewInt(2048) - power0.ConsensusMinerMinPower = big.NewInt(2048) + policy.SetMinVerifiedDealSize(abi.NewStoragePower(2048)) + policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) } func MakeHeaderVectors() []vectors.HeaderVector { diff --git a/chain/vm/gas.go b/chain/vm/gas.go index 12acf6a21..6802013e5 100644 --- a/chain/vm/gas.go +++ b/chain/vm/gas.go @@ -9,7 +9,6 @@ import ( addr "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime" vmr "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/ipfs/go-cid" ) @@ -210,7 +209,7 @@ func (ps pricedSyscalls) VerifyPoSt(vi proof.WindowPoStVerifyInfo) error { // the "parent grinding fault", in which case it must be the sibling of h1 (same parent tipset) and one of the // blocks in the parent of h2 (i.e. h2's grandparent). // Returns nil and an error if the headers don't prove a fault. -func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*runtime.ConsensusFault, error) { +func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*vmr.ConsensusFault, error) { ps.chargeGas(ps.pl.OnVerifyConsensusFault()) defer ps.chargeGas(gasOnActorExec) diff --git a/chain/vm/gas_v0.go b/chain/vm/gas_v0.go index e5ded440e..bfb49c345 100644 --- a/chain/vm/gas_v0.go +++ b/chain/vm/gas_v0.go @@ -8,7 +8,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" - "github.com/filecoin-project/specs-actors/actors/builtin" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" ) type scalingCost struct { @@ -112,14 +112,14 @@ func (pl *pricelistV0) OnMethodInvocation(value abi.TokenAmount, methodNum abi.M if big.Cmp(value, abi.NewTokenAmount(0)) != 0 { ret += pl.sendTransferFunds - if methodNum == builtin.MethodSend { + if methodNum == builtin0.MethodSend { // transfer only ret += pl.sendTransferOnlyPremium } extra += "t" } - if methodNum != builtin.MethodSend { + if methodNum != builtin0.MethodSend { extra += "i" // running actors is cheaper becase we hand over to actors ret += pl.sendInvokeMethod diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 0a83e273d..1e9f04081 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -6,91 +6,126 @@ import ( "fmt" "reflect" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" - builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" - account0 "github.com/filecoin-project/specs-actors/actors/builtin/account" - cron0 "github.com/filecoin-project/specs-actors/actors/builtin/cron" - init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" - market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" - miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" - msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" - paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" - power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" - reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" - system0 "github.com/filecoin-project/specs-actors/actors/builtin/system" - verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - vmr "github.com/filecoin-project/specs-actors/actors/runtime" + exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported" + exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported" + vmr "github.com/filecoin-project/specs-actors/v2/actors/runtime" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/exitcode" + rtt "github.com/filecoin-project/go-state-types/rt" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/aerrors" + "github.com/filecoin-project/lotus/chain/types" ) -type Invoker struct { - builtInCode map[cid.Cid]nativeCode - builtInState map[cid.Cid]reflect.Type +type ActorRegistry struct { + actors map[cid.Cid]*actorInfo +} + +// An ActorPredicate returns an error if the given actor is not valid for the given runtime environment (e.g., chain height, version, etc.). +type ActorPredicate func(vmr.Runtime, rtt.VMActor) error + +func ActorsVersionPredicate(ver actors.Version) ActorPredicate { + return func(rt vmr.Runtime, v rtt.VMActor) error { + nver := actors.VersionForNetwork(rt.NetworkVersion()) + if nver != ver { + return xerrors.Errorf("actor %s is a version %d actor; chain only supports actor version %d at height %d", v.Code(), ver, nver, rt.CurrEpoch()) + } + return nil + } } type invokeFunc func(rt vmr.Runtime, params []byte) ([]byte, aerrors.ActorError) type nativeCode []invokeFunc -func NewInvoker() *Invoker { - inv := &Invoker{ - builtInCode: make(map[cid.Cid]nativeCode), - builtInState: make(map[cid.Cid]reflect.Type), - } +type actorInfo struct { + methods nativeCode + vmActor rtt.VMActor + // TODO: consider making this a network version range? + predicate ActorPredicate +} + +func NewActorRegistry() *ActorRegistry { + inv := &ActorRegistry{actors: make(map[cid.Cid]*actorInfo)} + + // TODO: define all these properties on the actors themselves, in specs-actors. // add builtInCode using: register(cid, singleton) - // NETUPGRADE: register code IDs for v2, etc. - inv.Register(builtin0.SystemActorCodeID, system0.Actor{}, abi.EmptyValue{}) - inv.Register(builtin0.InitActorCodeID, init0.Actor{}, init0.State{}) - inv.Register(builtin0.RewardActorCodeID, reward0.Actor{}, reward0.State{}) - inv.Register(builtin0.CronActorCodeID, cron0.Actor{}, cron0.State{}) - inv.Register(builtin0.StoragePowerActorCodeID, power0.Actor{}, power0.State{}) - inv.Register(builtin0.StorageMarketActorCodeID, market0.Actor{}, market0.State{}) - inv.Register(builtin0.StorageMinerActorCodeID, miner0.Actor{}, miner0.State{}) - inv.Register(builtin0.MultisigActorCodeID, msig0.Actor{}, msig0.State{}) - inv.Register(builtin0.PaymentChannelActorCodeID, paych0.Actor{}, paych0.State{}) - inv.Register(builtin0.VerifiedRegistryActorCodeID, verifreg0.Actor{}, verifreg0.State{}) - inv.Register(builtin0.AccountActorCodeID, account0.Actor{}, account0.State{}) + inv.Register(ActorsVersionPredicate(actors.Version0), exported0.BuiltinActors()...) + inv.Register(ActorsVersionPredicate(actors.Version2), exported2.BuiltinActors()...) return inv } -func (inv *Invoker) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) { - - code, ok := inv.builtInCode[codeCid] +func (ar *ActorRegistry) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) { + act, ok := ar.actors[codeCid] if !ok { log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Receiver()) return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "no code for actor %s(%d)(%s)", codeCid, method, hex.EncodeToString(params)) } - if method >= abi.MethodNum(len(code)) || code[method] == nil { + if method >= abi.MethodNum(len(act.methods)) || act.methods[method] == nil { return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "no method %d on actor", method) } - return code[method](rt, params) - -} - -func (inv *Invoker) Register(c cid.Cid, instance Invokee, state interface{}) { - code, err := inv.transform(instance) - if err != nil { - panic(xerrors.Errorf("%s: %w", string(c.Hash()), err)) + if err := act.predicate(rt, act.vmActor); err != nil { + return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "unsupported actor: %s", err) } - inv.builtInCode[c] = code - inv.builtInState[c] = reflect.TypeOf(state) + return act.methods[method](rt, params) + } -type Invokee interface { +func (ar *ActorRegistry) Register(pred ActorPredicate, actors ...rtt.VMActor) { + if pred == nil { + pred = func(vmr.Runtime, rtt.VMActor) error { return nil } + } + for _, a := range actors { + code, err := ar.transform(a) + if err != nil { + panic(xerrors.Errorf("%s: %w", string(a.Code().Hash()), err)) + } + ar.actors[a.Code()] = &actorInfo{ + methods: code, + vmActor: a, + predicate: pred, + } + } +} + +func (ar *ActorRegistry) Create(codeCid cid.Cid, rt vmr.Runtime) (*types.Actor, aerrors.ActorError) { + act, ok := ar.actors[codeCid] + if !ok { + return nil, aerrors.Newf(exitcode.SysErrorIllegalArgument, "Can only create built-in actors.") + } + + if err := act.predicate(rt, act.vmActor); err != nil { + return nil, aerrors.Newf(exitcode.SysErrorIllegalArgument, "Cannot create actor: %w", err) + } + + if rtt.IsSingletonActor(act.vmActor) { + return nil, aerrors.Newf(exitcode.SysErrorIllegalArgument, "Can only have one instance of singleton actors.") + } + return &types.Actor{ + Code: codeCid, + Head: EmptyObjectCid, + Nonce: 0, + Balance: abi.NewTokenAmount(0), + }, nil +} + +type invokee interface { Exports() []interface{} } -func (*Invoker) transform(instance Invokee) (nativeCode, error) { +func (*ActorRegistry) transform(instance invokee) (nativeCode, error) { itype := reflect.TypeOf(instance) exports := instance.Exports() + runtimeType := reflect.TypeOf((*vmr.Runtime)(nil)).Elem() for i, m := range exports { i := i newErr := func(format string, args ...interface{}) error { @@ -111,7 +146,7 @@ func (*Invoker) transform(instance Invokee) (nativeCode, error) { return nil, newErr("wrong number of inputs should be: " + "vmr.Runtime, ") } - if t.In(0) != reflect.TypeOf((*vmr.Runtime)(nil)).Elem() { + if !runtimeType.Implements(t.In(0)) { return nil, newErr("first arguemnt should be vmr.Runtime") } if t.In(1).Kind() != reflect.Ptr { @@ -176,27 +211,22 @@ func DecodeParams(b []byte, out interface{}) error { return um.UnmarshalCBOR(bytes.NewReader(b)) } -func DumpActorState(code cid.Cid, b []byte) (interface{}, error) { - if code == builtin0.AccountActorCodeID { // Account code special case +func DumpActorState(act *types.Actor, b []byte) (interface{}, error) { + if builtin.IsAccountActor(act.Code) { // Account code special case return nil, nil } - i := NewInvoker() // TODO: register builtins in init block + i := NewActorRegistry() // TODO: register builtins in init block - typ, ok := i.builtInState[code] + actInfo, ok := i.actors[act.Code] if !ok { - return nil, xerrors.Errorf("state type for actor %s not found", code) - } - - rv := reflect.New(typ) - um, ok := rv.Interface().(cbg.CBORUnmarshaler) - if !ok { - return nil, xerrors.New("state type does not implement CBORUnmarshaler") + return nil, xerrors.Errorf("state type for actor %s not found", act.Code) } + um := actInfo.vmActor.State() if err := um.UnmarshalCBOR(bytes.NewReader(b)); err != nil { return nil, xerrors.Errorf("unmarshaling actor state: %w", err) } - return rv.Elem().Interface(), nil + return um, nil } diff --git a/chain/vm/invoker_test.go b/chain/vm/invoker_test.go index 3744aa8d2..4005dd42f 100644 --- a/chain/vm/invoker_test.go +++ b/chain/vm/invoker_test.go @@ -77,7 +77,7 @@ func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams) } func TestInvokerBasic(t *testing.T) { - inv := Invoker{} + inv := ActorRegistry{} code, err := inv.transform(basicContract{}) assert.NoError(t, err) diff --git a/chain/vm/mkactor.go b/chain/vm/mkactor.go index 43d2f9431..33884368f 100644 --- a/chain/vm/mkactor.go +++ b/chain/vm/mkactor.go @@ -6,11 +6,13 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/actors/aerrors" "github.com/filecoin-project/lotus/chain/types" @@ -39,7 +41,7 @@ func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, aer return nil, aerrors.Escalate(err, "registering actor address") } - act, aerr := makeActor(addr) + act, aerr := makeActor(actors.VersionForNetwork(rt.NetworkVersion()), addr) if aerr != nil { return nil, aerr } @@ -54,7 +56,7 @@ func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, aer } // call constructor on account - _, aerr = rt.internalSend(builtin.SystemActorAddr, addrID, builtin.MethodsAccount.Constructor, big.Zero(), p) + _, aerr = rt.internalSend(builtin0.SystemActorAddr, addrID, builtin0.MethodsAccount.Constructor, big.Zero(), p) if aerr != nil { return nil, aerrors.Wrap(aerr, "failed to invoke account constructor") } @@ -66,12 +68,10 @@ func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, aer return act, nil } -func makeActor(addr address.Address) (*types.Actor, aerrors.ActorError) { +func makeActor(ver actors.Version, addr address.Address) (*types.Actor, aerrors.ActorError) { switch addr.Protocol() { - case address.BLS: - return NewBLSAccountActor(), nil - case address.SECP256K1: - return NewSecp256k1AccountActor(), nil + case address.BLS, address.SECP256K1: + return newAccountActor(ver), nil case address.ID: return nil, aerrors.Newf(exitcode.SysErrInvalidReceiver, "no actor with given ID: %s", addr) case address.Actor: @@ -81,19 +81,19 @@ func makeActor(addr address.Address) (*types.Actor, aerrors.ActorError) { } } -func NewBLSAccountActor() *types.Actor { +func newAccountActor(ver actors.Version) *types.Actor { + // TODO: ActorsUpgrade use a global actor registry? + var code cid.Cid + switch ver { + case actors.Version0: + code = builtin0.AccountActorCodeID + case actors.Version2: + code = builtin2.AccountActorCodeID + default: + panic("unsupported actors version") + } nact := &types.Actor{ - Code: builtin.AccountActorCodeID, - Balance: types.NewInt(0), - Head: EmptyObjectCid, - } - - return nact -} - -func NewSecp256k1AccountActor() *types.Actor { - nact := &types.Actor{ - Code: builtin.AccountActorCodeID, + Code: code, Balance: types.NewInt(0), Head: EmptyObjectCid, } diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 72dd413ed..472017a00 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -9,14 +9,13 @@ 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/cbor" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-state-types/network" rtt "github.com/filecoin-project/go-state-types/rt" - "github.com/filecoin-project/specs-actors/actors/builtin" rt0 "github.com/filecoin-project/specs-actors/actors/runtime" + rt2 "github.com/filecoin-project/specs-actors/v2/actors/runtime" "github.com/ipfs/go-cid" ipldcbor "github.com/ipfs/go-ipld-cbor" "go.opencensus.io/trace" @@ -110,6 +109,7 @@ func (rt *Runtime) StorePut(x cbor.Marshaler) cid.Cid { } var _ rt0.Runtime = (*Runtime)(nil) +var _ rt2.Runtime = (*Runtime)(nil) func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) { defer func() { @@ -215,12 +215,9 @@ func (rt *Runtime) NewActorAddress() address.Address { } func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) { - if !builtin.IsBuiltinActor(codeID) { - rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only create built-in actors.") - } - - if builtin.IsSingletonActor(codeID) { - rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only have one instance of singleton actors.") + act, aerr := rt.vm.areg.Create(codeID, rt) + if aerr != nil { + rt.Abortf(aerr.RetCode(), aerr.Error()) } _, err := rt.state.GetActor(address) @@ -230,12 +227,7 @@ func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) { rt.chargeGas(rt.Pricelist().OnCreateActor()) - err = rt.state.SetActor(address, &types.Actor{ - Code: codeID, - Head: EmptyObjectCid, - Nonce: 0, - Balance: big.Zero(), - }) + err = rt.state.SetActor(address, act) if err != nil { panic(aerrors.Fatalf("creating actor entry: %v", err)) } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 44979454f..1361c6fbe 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -8,6 +8,8 @@ import ( "sync/atomic" "time" + "github.com/filecoin-project/lotus/chain/actors/builtin" + block "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" @@ -23,7 +25,6 @@ import ( "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-state-types/network" - "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/adt" @@ -152,7 +153,7 @@ type VM struct { cst *cbor.BasicIpldStore buf *bufbstore.BufferedBS blockHeight abi.ChainEpoch - inv *Invoker + areg *ActorRegistry rand Rand circSupplyCalc CircSupplyCalculator ntwkVersion NtwkVersionGetter @@ -186,7 +187,7 @@ func NewVM(ctx context.Context, opts *VMOpts) (*VM, error) { cst: cst, buf: buf, blockHeight: opts.Epoch, - inv: NewInvoker(), + areg: NewActorRegistry(), rand: opts.Rand, // TODO: Probably should be a syscall circSupplyCalc: opts.CircSupplyCalc, ntwkVersion: opts.NtwkVersion, @@ -403,7 +404,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, } // this should never happen, but is currently still exercised by some tests - if !fromActor.IsAccountActor() { + if !builtin.IsAccountActor(fromActor.Code) { gasOutputs := ZeroGasOutputs() gasOutputs.MinerPenalty = minerPenaltyAmount return &ApplyRet{ @@ -741,15 +742,15 @@ func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params defer func() { rt.ctx = oldCtx }() - ret, err := vm.inv.Invoke(act.Code, rt, method, params) + ret, err := vm.areg.Invoke(act.Code, rt, method, params) if err != nil { return nil, err } return ret, nil } -func (vm *VM) SetInvoker(i *Invoker) { - vm.inv = i +func (vm *VM) SetInvoker(i *ActorRegistry) { + vm.areg = i } func (vm *VM) GetNtwkVersion(ctx context.Context, ce abi.ChainEpoch) network.Version { diff --git a/cli/multisig.go b/cli/multisig.go index 5b0977382..6b3867cb3 100644 --- a/cli/multisig.go +++ b/cli/multisig.go @@ -9,6 +9,10 @@ import ( "strconv" "text/tabwriter" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/go-state-types/big" @@ -20,7 +24,6 @@ import ( "github.com/urfave/cli/v2" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/builtin" init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" @@ -356,7 +359,7 @@ var msigProposeCmd = &cli.Command{ return fmt.Errorf("failed to look up multisig %s: %w", msig, err) } - if !act.IsMultisigActor() { + if !builtin.IsMultisigActor(act.Code) { return fmt.Errorf("actor %s is not a multisig actor", msig) } @@ -1029,7 +1032,7 @@ var msigLockProposeCmd = &cli.Command{ return actErr } - msgCid, err := api.MsigPropose(ctx, msig, msig, big.Zero(), from, uint64(builtin.MethodsMultisig.LockBalance), params) + msgCid, err := api.MsigPropose(ctx, msig, msig, big.Zero(), from, uint64(builtin2.MethodsMultisig.LockBalance), params) if err != nil { return err } @@ -1126,7 +1129,7 @@ var msigLockApproveCmd = &cli.Command{ return actErr } - msgCid, err := api.MsigApprove(ctx, msig, txid, prop, msig, big.Zero(), from, uint64(builtin.MethodsMultisig.LockBalance), params) + msgCid, err := api.MsigApprove(ctx, msig, txid, prop, msig, big.Zero(), from, uint64(builtin2.MethodsMultisig.LockBalance), params) if err != nil { return err } @@ -1218,7 +1221,7 @@ var msigLockCancelCmd = &cli.Command{ return actErr } - msgCid, err := api.MsigCancel(ctx, msig, txid, msig, big.Zero(), from, uint64(builtin.MethodsMultisig.LockBalance), params) + msgCid, err := api.MsigCancel(ctx, msig, txid, msig, big.Zero(), from, uint64(builtin2.MethodsMultisig.LockBalance), params) if err != nil { return err } diff --git a/cli/paych.go b/cli/paych.go index dc5b54c4a..1d5e304c3 100644 --- a/cli/paych.go +++ b/cli/paych.go @@ -14,10 +14,10 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/urfave/cli/v2" - types "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" + "github.com/filecoin-project/lotus/chain/types" ) var paychCmd = &cli.Command{ @@ -404,7 +404,7 @@ var paychVoucherCheckCmd = &cli.Command{ return err } - sv, err := types.DecodeSignedVoucher(cctx.Args().Get(1)) + sv, err := paych.DecodeSignedVoucher(cctx.Args().Get(1)) if err != nil { return err } @@ -440,7 +440,7 @@ var paychVoucherAddCmd = &cli.Command{ return err } - sv, err := types.DecodeSignedVoucher(cctx.Args().Get(1)) + sv, err := paych.DecodeSignedVoucher(cctx.Args().Get(1)) if err != nil { return err } @@ -598,7 +598,7 @@ var paychVoucherSubmitCmd = &cli.Command{ return err } - sv, err := types.DecodeSignedVoucher(cctx.Args().Get(1)) + sv, err := paych.DecodeSignedVoucher(cctx.Args().Get(1)) if err != nil { return err } diff --git a/cli/state.go b/cli/state.go index 7baf57df2..cb1c974a7 100644 --- a/cli/state.go +++ b/cli/state.go @@ -14,7 +14,7 @@ import ( "strings" "time" - "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/multiformats/go-multiaddr" @@ -30,8 +30,6 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/exitcode" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/exported" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/apibstore" @@ -1534,28 +1532,18 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er return nil, nil } - var target runtime.Invokee - for _, actor := range exported.BuiltinActors() { - if actor.Code() == act { - target = actor - } - } - if target == nil { + // TODO: consider moving this to a dedicated helper + actMeta, ok := stmgr.MethodsMap[act] + if !ok { return nil, fmt.Errorf("unknown actor %s", act) } - methods := target.Exports() - if uint64(len(methods)) <= method || methods[method] == nil { + + methodMeta, ok := actMeta[abi.MethodNum(method)] + if !ok { return nil, fmt.Errorf("unknown method %d for actor %s", method, act) } - f := methods[method] - - rf := reflect.TypeOf(f) - if rf.NumIn() != 2 { - return nil, fmt.Errorf("expected referenced method to have three arguments") - } - - paramObj := rf.In(1).Elem() + paramObj := methodMeta.Params if paramObj.NumField() != len(args) { return nil, fmt.Errorf("not enough arguments given to call that method (expecting %d)", paramObj.NumField()) } diff --git a/cmd/lotus-chainwatch/processor/common_actors.go b/cmd/lotus-chainwatch/processor/common_actors.go index 56520880c..0f2c0d2ea 100644 --- a/cmd/lotus-chainwatch/processor/common_actors.go +++ b/cmd/lotus-chainwatch/processor/common_actors.go @@ -9,12 +9,15 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + + "github.com/filecoin-project/lotus/chain/actors/builtin" _init "github.com/filecoin-project/lotus/chain/actors/builtin/init" "github.com/filecoin-project/lotus/chain/events/state" "github.com/filecoin-project/lotus/chain/types" cw_util "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/util" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/ipfs/go-cid" ) func (p *Processor) setupCommonActors() error { @@ -135,15 +138,15 @@ func (p Processor) storeActorAddresses(ctx context.Context, actors map[cid.Cid]A addressToID := map[address.Address]address.Address{} // HACK until genesis storage is figured out: - addressToID[builtin.SystemActorAddr] = builtin.SystemActorAddr - addressToID[builtin.InitActorAddr] = builtin.InitActorAddr - addressToID[builtin.RewardActorAddr] = builtin.RewardActorAddr - addressToID[builtin.CronActorAddr] = builtin.CronActorAddr - addressToID[builtin.StoragePowerActorAddr] = builtin.StoragePowerActorAddr - addressToID[builtin.StorageMarketActorAddr] = builtin.StorageMarketActorAddr - addressToID[builtin.VerifiedRegistryActorAddr] = builtin.VerifiedRegistryActorAddr - addressToID[builtin.BurntFundsActorAddr] = builtin.BurntFundsActorAddr - initActor, err := p.node.StateGetActor(ctx, builtin.InitActorAddr, types.EmptyTSK) + addressToID[builtin2.SystemActorAddr] = builtin2.SystemActorAddr + addressToID[builtin2.InitActorAddr] = builtin2.InitActorAddr + addressToID[builtin2.RewardActorAddr] = builtin2.RewardActorAddr + addressToID[builtin2.CronActorAddr] = builtin2.CronActorAddr + addressToID[builtin2.StoragePowerActorAddr] = builtin2.StoragePowerActorAddr + addressToID[builtin2.StorageMarketActorAddr] = builtin2.StorageMarketActorAddr + addressToID[builtin2.VerifiedRegistryActorAddr] = builtin2.VerifiedRegistryActorAddr + addressToID[builtin2.BurntFundsActorAddr] = builtin2.BurntFundsActorAddr + initActor, err := p.node.StateGetActor(ctx, builtin2.InitActorAddr, types.EmptyTSK) if err != nil { return err } diff --git a/cmd/lotus-pcr/main.go b/cmd/lotus-pcr/main.go index 4ce5bbb9f..769fc4bb2 100644 --- a/cmd/lotus-pcr/main.go +++ b/cmd/lotus-pcr/main.go @@ -14,7 +14,9 @@ import ( "strconv" "time" - "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors/builtin" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/go-state-types/network" @@ -850,14 +852,14 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu continue } - if !a.IsStorageMinerActor() { + if !builtin.IsStorageMinerActor(a.Code) { continue } var messageMethod string switch m.Method { - case builtin.MethodsMiner.ProveCommitSector: + case builtin0.MethodsMiner.ProveCommitSector: if !r.proveCommitEnabled { continue } @@ -904,7 +906,7 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu } refundValue = collateral - case builtin.MethodsMiner.PreCommitSector: + case builtin0.MethodsMiner.PreCommitSector: if !r.preCommitEnabled { continue } diff --git a/cmd/lotus-shed/balances.go b/cmd/lotus-shed/balances.go index 1c89a00cf..fba6d7724 100644 --- a/cmd/lotus-shed/balances.go +++ b/cmd/lotus-shed/balances.go @@ -6,7 +6,7 @@ import ( "strconv" "github.com/docker/go-units" - lotusbuiltin "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/builtin/power" "github.com/filecoin-project/lotus/chain/actors/builtin/reward" @@ -97,7 +97,7 @@ var chainBalanceCmd = &cli.Command{ Type: string(act.Code.Hash()[2:]), } - if act.IsStorageMinerActor() { + if builtin.IsStorageMinerActor(act.Code) { pow, err := api.StateMinerPower(ctx, addr, tsk) if err != nil { return xerrors.Errorf("failed to get power: %w", err) @@ -198,7 +198,7 @@ var chainBalanceStateCmd = &cli.Command{ PreCommits: types.FIL(big.NewInt(0)), } - if minerInfo && act.IsStorageMinerActor() { + if minerInfo && builtin.IsStorageMinerActor(act.Code) { pow, _, _, err := stmgr.GetPowerRaw(ctx, sm, sroot, addr) if err != nil { return xerrors.Errorf("failed to get power: %w", err) @@ -322,7 +322,7 @@ var chainPledgeCmd = &cli.Command{ } var ( - powerSmoothed lotusbuiltin.FilterEstimate + powerSmoothed builtin.FilterEstimate pledgeCollateral abi.TokenAmount ) if act, err := state.GetActor(power.Address); err != nil { diff --git a/cmd/lotus-shed/genesis-verify.go b/cmd/lotus-shed/genesis-verify.go index da2c82359..9a47d6561 100644 --- a/cmd/lotus-shed/genesis-verify.go +++ b/cmd/lotus-shed/genesis-verify.go @@ -6,6 +6,8 @@ import ( "os" "sort" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/fatih/color" "github.com/ipfs/go-datastore" cbor "github.com/ipfs/go-ipld-cbor" @@ -95,14 +97,14 @@ var genesisVerifyCmd = &cli.Command{ if err := stree.ForEach(func(addr address.Address, act *types.Actor) error { switch { - case act.IsStorageMinerActor(): + case builtin.IsStorageMinerActor(act.Code): _, err := miner.Load(store, act) if err != nil { return xerrors.Errorf("miner actor: %w", err) } // TODO: actually verify something here? kminers[addr] = minerInfo{} - case act.IsMultisigActor(): + case builtin.IsMultisigActor(act.Code): st, err := multisig.Load(store, act) if err != nil { return xerrors.Errorf("multisig actor: %w", err) @@ -123,7 +125,7 @@ var genesisVerifyCmd = &cli.Command{ Threshold: threshold, } msigAddrs = append(msigAddrs, addr) - case act.IsAccountActor(): + case builtin.IsAccountActor(act.Code): st, err := account.Load(store, act) if err != nil { // TODO: magik6k: this _used_ to log instead of failing, why? diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go index 165c01432..d70cd4b71 100644 --- a/cmd/lotus-shed/mempool-stats.go +++ b/cmd/lotus-shed/mempool-stats.go @@ -18,6 +18,7 @@ import ( "github.com/filecoin-project/go-address" lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" ) @@ -122,7 +123,7 @@ var mpoolStatsCmd = &cli.Command{ return false, err } - ism := act.IsStorageMinerActor() + ism := builtin.IsStorageMinerActor(act.Code) mcache[addr] = ism return ism, nil } diff --git a/cmd/tvx/actor_mapping.go b/cmd/tvx/actor_mapping.go deleted file mode 100644 index 8c306aca0..000000000 --- a/cmd/tvx/actor_mapping.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "reflect" - - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/ipfs/go-cid" - "github.com/multiformats/go-multihash" -) - -var ActorMethodTable = make(map[string][]string, 64) - -var Actors = map[cid.Cid]interface{}{ - builtin.InitActorCodeID: builtin.MethodsInit, - builtin.CronActorCodeID: builtin.MethodsCron, - builtin.AccountActorCodeID: builtin.MethodsAccount, - builtin.StoragePowerActorCodeID: builtin.MethodsPower, - builtin.StorageMinerActorCodeID: builtin.MethodsMiner, - builtin.StorageMarketActorCodeID: builtin.MethodsMarket, - builtin.PaymentChannelActorCodeID: builtin.MethodsPaych, - builtin.MultisigActorCodeID: builtin.MethodsMultisig, - builtin.RewardActorCodeID: builtin.MethodsReward, - builtin.VerifiedRegistryActorCodeID: builtin.MethodsVerifiedRegistry, -} - -func init() { - for code, methods := range Actors { - cmh, err := multihash.Decode(code.Hash()) // identity hash. - if err != nil { - panic(err) - } - - var ( - aname = string(cmh.Digest) - rt = reflect.TypeOf(methods) - nf = rt.NumField() - ) - - ActorMethodTable[aname] = append(ActorMethodTable[aname], "Send") - for i := 0; i < nf; i++ { - ActorMethodTable[aname] = append(ActorMethodTable[aname], rt.Field(i).Name) - } - } -} diff --git a/cmd/tvx/extract_many.go b/cmd/tvx/extract_many.go index 9679a1dbd..fe0ce6a6c 100644 --- a/cmd/tvx/extract_many.go +++ b/cmd/tvx/extract_many.go @@ -12,10 +12,14 @@ import ( "strings" "github.com/fatih/color" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/exitcode" "github.com/hashicorp/go-multierror" + "github.com/ipfs/go-cid" + "github.com/multiformats/go-multihash" "github.com/urfave/cli/v2" + "github.com/filecoin-project/lotus/chain/stmgr" lcli "github.com/filecoin-project/lotus/cli" ) @@ -118,6 +122,8 @@ func runExtractMany(c *cli.Context) error { log.Println(color.GreenString("csv sanity check succeeded; header contains fields: %v", header)) } + codeCidBuilder := cid.V1Builder{Codec: cid.Raw, MhType: multihash.IDENTITY} + var ( generated []string merr = new(multierror.Error) @@ -133,7 +139,7 @@ func runExtractMany(c *cli.Context) error { return fmt.Errorf("failed to read row: %w", err) } var ( - cid = row[0] + mcid = row[0] actorcode = row[1] methodnumstr = row[2] exitcodestr = row[3] @@ -155,13 +161,18 @@ func runExtractMany(c *cli.Context) error { return fmt.Errorf("invalid method number: %s", methodnumstr) } + codeCid, err := codeCidBuilder.Sum([]byte(actorcode)) + if err != nil { + return fmt.Errorf("failed to compute actor code CID") + } + // Lookup the method in actor method table. - if m, ok := ActorMethodTable[actorcode]; !ok { + if m, ok := stmgr.MethodsMap[codeCid]; !ok { return fmt.Errorf("unrecognized actor: %s", actorcode) } else if methodnum >= len(m) { return fmt.Errorf("unrecognized method number for actor %s: %d", actorcode, methodnum) } else { - methodname = m[methodnum] + methodname = m[abi.MethodNum(methodnum)].Name } // exitcode string representations are of kind ErrType(0); strip out @@ -181,14 +192,14 @@ func runExtractMany(c *cli.Context) error { id: id, block: block, class: "message", - cid: cid, + cid: mcid, file: file, retain: "accessed-cids", precursor: PrecursorSelectSender, } if err := doExtract(ctx, fapi, opts); err != nil { - log.Println(color.RedString("failed to extract vector for message %s: %s; queuing for 'canonical' precursor selection", cid, err)) + log.Println(color.RedString("failed to extract vector for message %s: %s; queuing for 'canonical' precursor selection", mcid, err)) retry = append(retry, opts) continue } diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go index 477204374..d5e0b4352 100644 --- a/conformance/chaos/actor.go +++ b/conformance/chaos/actor.go @@ -3,7 +3,9 @@ package chaos import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/go-state-types/rt" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/ipfs/go-cid" @@ -86,7 +88,11 @@ func (a Actor) Exports() []interface{} { } } -var _ runtime.Invokee = Actor{} +func (a Actor) Code() cid.Cid { return ChaosActorCodeCID } +func (a Actor) State() cbor.Er { return new(State) } +func (a Actor) IsSingleton() bool { return true } + +var _ rt.VMActor = Actor{} // SendArgs are the arguments for the Send method. type SendArgs struct { diff --git a/conformance/driver.go b/conformance/driver.go index 9ced12d74..5648084ce 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -167,7 +167,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP // dummy state manager; only to reference the GetNetworkVersion method, // which does not depend on state. - sm := new(stmgr.StateManager) + sm := stmgr.NewStateManager(nil) vmOpts := &vm.VMOpts{ StateBase: params.Preroot, @@ -187,11 +187,11 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP return nil, cid.Undef, err } - invoker := vm.NewInvoker() + invoker := vm.NewActorRegistry() // register the chaos actor if required by the vector. if chaosOn, ok := d.selector["chaos_actor"]; ok && chaosOn == "true" { - invoker.Register(chaos.ChaosActorCodeCID, chaos.Actor{}, chaos.State{}) + invoker.Register(nil, chaos.Actor{}) } lvm.SetInvoker(invoker) diff --git a/conformance/runner.go b/conformance/runner.go index 2db53b3e4..626545b2b 100644 --- a/conformance/runner.go +++ b/conformance/runner.go @@ -233,7 +233,12 @@ func writeStateToTempCAR(bs blockstore.Blockstore, roots ...cid.Cid) (string, er if link.Cid.Prefix().Codec == cid.FilCommitmentSealed || link.Cid.Prefix().Codec == cid.FilCommitmentUnsealed { continue } - out = append(out, link) + // ignore things we don't have, the state tree is incomplete. + if has, err := bs.Has(link.Cid); err != nil { + return nil, err + } else if has { + out = append(out, link) + } } return out, nil } diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index d03bb94ed..1bae2c1e6 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -3863,7 +3863,7 @@ Inputs: ] ``` -Response: `3` +Response: `4` ### StateReadState StateReadState returns the indicated actor's state. diff --git a/extern/fil-blst b/extern/fil-blst index 8609119cf..5f93488fc 160000 --- a/extern/fil-blst +++ b/extern/fil-blst @@ -1 +1 @@ -Subproject commit 8609119cf4595d1741139c24378fcd8bc4f1c475 +Subproject commit 5f93488fc0dbfb450f2355269f18fc67010d59bb diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index 57e38efe4..f640612a1 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit 57e38efe4943f09d3127dcf6f0edd614e6acf68e +Subproject commit f640612a1a1f7a2dd8b3a49e1531db0aa0f63447 diff --git a/extern/oni b/extern/oni index 9a0d5cd73..dbee44e4f 160000 --- a/extern/oni +++ b/extern/oni @@ -1 +1 @@ -Subproject commit 9a0d5cd739de77b357589ac1fc8b756ed27299be +Subproject commit dbee44e4f940a502971f17116ccbba61ceaf2674 diff --git a/extern/storage-sealing/checks.go b/extern/storage-sealing/checks.go index 49994024f..1010d31b2 100644 --- a/extern/storage-sealing/checks.go +++ b/extern/storage-sealing/checks.go @@ -4,11 +4,9 @@ import ( "bytes" "context" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/policy" - "github.com/filecoin-project/lotus/build" - miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" - proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof" "golang.org/x/xerrors" @@ -102,16 +100,10 @@ func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, t return &ErrApi{xerrors.Errorf("calling StateNetworkVersion: %w", err)} } - var msd abi.ChainEpoch - if nv < build.ActorUpgradeNetworkVersion { - msd = miner0.MaxSealDuration[si.SectorType] - } else { - // TODO: ActorUpgrade(use MaxProveCommitDuration) - msd = 0 - } + msd := policy.GetMaxProveCommitDuration(actors.VersionForNetwork(nv), si.SectorType) - if height-(si.TicketEpoch+SealRandomnessLookback) > msd { - return &ErrExpiredTicket{xerrors.Errorf("ticket expired: seal height: %d, head: %d", si.TicketEpoch+SealRandomnessLookback, height)} + if height-(si.TicketEpoch+policy.SealRandomnessLookback) > msd { + return &ErrExpiredTicket{xerrors.Errorf("ticket expired: seal height: %d, head: %d", si.TicketEpoch+policy.SealRandomnessLookback, height)} } pci, err := api.StateSectorPreCommitInfo(ctx, maddr, si.SectorNumber, tok) diff --git a/extern/storage-sealing/constants.go b/extern/storage-sealing/constants.go index 8c7fa5abc..d6aba1814 100644 --- a/extern/storage-sealing/constants.go +++ b/extern/storage-sealing/constants.go @@ -1,11 +1,4 @@ package sealing -import ( - miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" -) - -// Epochs -const SealRandomnessLookback = miner0.ChainFinality - // Epochs const InteractivePoRepConfidence = 6 diff --git a/extern/storage-sealing/states_failed.go b/extern/storage-sealing/states_failed.go index 88bf2d58d..d22830253 100644 --- a/extern/storage-sealing/states_failed.go +++ b/extern/storage-sealing/states_failed.go @@ -4,14 +4,14 @@ import ( "bytes" "time" - "github.com/filecoin-project/lotus/chain/actors/builtin/miner" - "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-statemachine" - "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/lotus/extern/sector-storage/zerocomm" ) diff --git a/extern/storage-sealing/states_sealing.go b/extern/storage-sealing/states_sealing.go index a4e852454..96589bcd2 100644 --- a/extern/storage-sealing/states_sealing.go +++ b/extern/storage-sealing/states_sealing.go @@ -4,10 +4,9 @@ import ( "bytes" "context" - "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors/policy" - miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "golang.org/x/xerrors" @@ -60,7 +59,7 @@ func (m *Sealing) getTicket(ctx statemachine.Context, sector SectorInfo) (abi.Se return nil, 0, nil } - ticketEpoch := epoch - SealRandomnessLookback + ticketEpoch := epoch - policy.SealRandomnessLookback buf := new(bytes.Buffer) if err := m.maddr.MarshalCBOR(buf); err != nil { return nil, 0, err @@ -189,13 +188,7 @@ func (m *Sealing) handlePreCommitting(ctx statemachine.Context, sector SectorInf return ctx.Send(SectorSealPreCommit1Failed{xerrors.Errorf("failed to get network version: %w", err)}) } - var msd abi.ChainEpoch - if nv < build.ActorUpgradeNetworkVersion { - msd = miner0.MaxSealDuration[sector.SectorType] - } else { - // TODO: ActorUpgrade(use MaxProveCommitDuration) - msd = 0 - } + msd := policy.GetMaxProveCommitDuration(actors.VersionForNetwork(nv), sector.SectorType) if minExpiration := height + msd + miner.MinSectorExpiration + 10; expiration < minExpiration { expiration = minExpiration diff --git a/extern/storage-sealing/types.go b/extern/storage-sealing/types.go index c044defd3..046271a7f 100644 --- a/extern/storage-sealing/types.go +++ b/extern/storage-sealing/types.go @@ -9,7 +9,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/exitcode" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-storage/storage" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" @@ -82,7 +82,7 @@ type SectorInfo struct { CommR *cid.Cid Proof []byte - PreCommitInfo *miner.SectorPreCommitInfo + PreCommitInfo *miner0.SectorPreCommitInfo PreCommitDeposit big.Int PreCommitMessage *cid.Cid PreCommitTipSet TipSetToken diff --git a/go.mod b/go.mod index 024a6a204..a160389b0 100644 --- a/go.mod +++ b/go.mod @@ -33,11 +33,12 @@ require ( github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 - github.com/filecoin-project/go-state-types v0.0.0-20200911004822-964d6c679cfc + github.com/filecoin-project/go-state-types v0.0.0-20200928172055-2df22083d8ab github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b - github.com/filecoin-project/specs-actors v0.9.11 + github.com/filecoin-project/specs-actors v0.9.12 + github.com/filecoin-project/specs-actors/v2 v2.0.0-20201002200957-bdd876b3bbe9 github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 github.com/filecoin-project/test-vectors/schema v0.0.3 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 diff --git a/go.sum b/go.sum index e820ede3a..5a00fff77 100644 --- a/go.sum +++ b/go.sum @@ -248,6 +248,8 @@ github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3 github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= +github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM= +github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0/go.mod h1:7aWZdaQ1b16BVoQUYR+eEvrDCGJoPLxFpDynFjYfBjI= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI= @@ -259,8 +261,8 @@ github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/g github.com/filecoin-project/go-state-types v0.0.0-20200903145444-247639ffa6ad/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-state-types v0.0.0-20200904021452-1883f36ca2f4/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= -github.com/filecoin-project/go-state-types v0.0.0-20200911004822-964d6c679cfc h1:1vr/LoqGq5m5g37Q3sNSAjfwF1uJY0zmiHcvnxY6hik= -github.com/filecoin-project/go-state-types v0.0.0-20200911004822-964d6c679cfc/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-state-types v0.0.0-20200928172055-2df22083d8ab h1:cEDC5Ei8UuT99hPWhCjA72SM9AuRtnpvdSTIYbnzN8I= +github.com/filecoin-project/go-state-types v0.0.0-20200928172055-2df22083d8ab/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe h1:dF8u+LEWeIcTcfUcCf3WFVlc81Fr2JKg8zPzIbBDKDw= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= @@ -270,8 +272,10 @@ github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= github.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4= github.com/filecoin-project/specs-actors v0.9.7/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= -github.com/filecoin-project/specs-actors v0.9.11 h1:TnpG7HAeiUrfj0mJM7UaPW0P2137H62RGof7ftT5Mas= -github.com/filecoin-project/specs-actors v0.9.11/go.mod h1:czlvLQGEX0fjLLfdNHD7xLymy6L3n7aQzRWzsYGf+ys= +github.com/filecoin-project/specs-actors v0.9.12 h1:iIvk58tuMtmloFNHhAOQHG+4Gci6Lui0n7DYQGi3cJk= +github.com/filecoin-project/specs-actors v0.9.12/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao= +github.com/filecoin-project/specs-actors/v2 v2.0.0-20201002200957-bdd876b3bbe9 h1:UXVcGwUD9GJYNcgfGbf7ok790wrunvUhl5ZlgApGhGs= +github.com/filecoin-project/specs-actors/v2 v2.0.0-20201002200957-bdd876b3bbe9/go.mod h1:52FuQUNDXq2WDg+6+UOhkqBuNc2e62h9BCIB67Bluxg= github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk= github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.3 h1:1zuBo25B3016inbygYLgYFdpJ2m1BDTbAOCgABRleiU= @@ -1396,6 +1400,7 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:X github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20200806213330-63aa96ca5488/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200810223238-211df3b9e24c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163 h1:TtcUeY2XZSriVWR1pXyfCBWIf/NGC2iUdNw1lofUjUU= diff --git a/journal/registry_test.go b/journal/registry_test.go index 9d2085c12..bce3d3f17 100644 --- a/journal/registry_test.go +++ b/journal/registry_test.go @@ -14,7 +14,7 @@ func TestDisabledEvents(t *testing.T) { registry := NewEventTypeRegistry(dis) reg1 := registry.RegisterEventType("system1", "disabled1") - reg2 := registry.RegisterEventType("system2", "disabled2") + reg2 := registry.RegisterEventType("system1", "disabled2") req.False(reg1.Enabled()) req.False(reg2.Enabled()) @@ -29,21 +29,21 @@ func TestDisabledEvents(t *testing.T) { t.Run("direct", test(DisabledEvents{ EventType{System: "system1", Event: "disabled1"}, - EventType{System: "system2", Event: "disabled2"}, + EventType{System: "system1", Event: "disabled2"}, })) - dis, err := ParseDisabledEvents("system1:disabled1,system2:disabled2") + dis, err := ParseDisabledEvents("system1:disabled1,system1:disabled2") req.NoError(err) t.Run("parsed", test(dis)) - dis, err = ParseDisabledEvents(" system1:disabled1 , system2:disabled2 ") + dis, err = ParseDisabledEvents(" system1:disabled1 , system1:disabled2 ") req.NoError(err) t.Run("parsed_spaces", test(dis)) } func TestParseDisableEvents(t *testing.T) { - _, err := ParseDisabledEvents("system1:disabled1:failed,system2:disabled2") + _, err := ParseDisabledEvents("system1:disabled1:failed,system1:disabled2") require.Error(t, err) } diff --git a/journal/types.go b/journal/types.go index 56c7d4bc0..5b51ed4c8 100644 --- a/journal/types.go +++ b/journal/types.go @@ -22,7 +22,7 @@ var ( // DisabledEvents is the set of event types whose journaling is suppressed. type DisabledEvents []EventType -// ParseDisabledEvents parses a string of the form: "system1:event1,system2:event2[,...]" +// ParseDisabledEvents parses a string of the form: "system1:event1,system1:event2[,...]" // into a DisabledEvents object, returning an error if the string failed to parse. // // It sanitizes strings via strings.TrimSpace. diff --git a/lotuspond/front/src/chain/methodgen.go b/lotuspond/front/src/chain/methodgen.go index 3197803fe..5a00d5e6e 100644 --- a/lotuspond/front/src/chain/methodgen.go +++ b/lotuspond/front/src/chain/methodgen.go @@ -4,12 +4,11 @@ import ( "encoding/json" "io/ioutil" "os" - "reflect" - "github.com/ipfs/go-cid" "github.com/multiformats/go-multihash" - "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/stmgr" ) func main() { @@ -17,6 +16,7 @@ func main() { panic(err) // note: must run in lotuspond/front/src/chain } + // TODO: ActorUpgrade: this is going to be a problem. names := map[string]string{ "system": "fil/1/system", "init": "fil/1/init", @@ -42,33 +42,25 @@ func main() { } } - methods := map[cid.Cid]interface{}{ - // builtin.SystemActorCodeID: builtin.MethodsSystem - apparently it doesn't have methods - builtin.InitActorCodeID: builtin.MethodsInit, - builtin.CronActorCodeID: builtin.MethodsCron, - builtin.AccountActorCodeID: builtin.MethodsAccount, - builtin.StoragePowerActorCodeID: builtin.MethodsPower, - builtin.StorageMinerActorCodeID: builtin.MethodsMiner, - builtin.StorageMarketActorCodeID: builtin.MethodsMarket, - builtin.PaymentChannelActorCodeID: builtin.MethodsPaych, - builtin.MultisigActorCodeID: builtin.MethodsMultisig, - builtin.RewardActorCodeID: builtin.MethodsReward, - builtin.VerifiedRegistryActorCodeID: builtin.MethodsVerifiedRegistry, - } - out := map[string][]string{} - for c, methods := range methods { + + for c, methods := range stmgr.MethodsMap { cmh, err := multihash.Decode(c.Hash()) if err != nil { panic(err) } - rt := reflect.TypeOf(methods) - nf := rt.NumField() + name := string(cmh.Digest) + remaining := len(methods) - out[string(cmh.Digest)] = append(out[string(cmh.Digest)], "Send") - for i := 0; i < nf; i++ { - out[string(cmh.Digest)] = append(out[string(cmh.Digest)], rt.Field(i).Name) + // iterate over actor methods in order. + for i := abi.MethodNum(0); remaining > 0; i++ { + m, ok := methods[i] + if !ok { + continue + } + out[name] = append(out[name], m.Name) + remaining-- } } diff --git a/lotuspond/front/src/chain/methods.json b/lotuspond/front/src/chain/methods.json index ce4919cc4..5e15b053b 100644 --- a/lotuspond/front/src/chain/methods.json +++ b/lotuspond/front/src/chain/methods.json @@ -87,6 +87,10 @@ "SubmitPoRepForBulkVerify", "CurrentTotalPower" ], + "fil/1/system": [ + "Send", + "Constructor" + ], "fil/1/verifiedregistry": [ "Send", "Constructor", @@ -95,5 +99,107 @@ "AddVerifiedClient", "UseBytes", "RestoreBytes" + ], + "fil/2/account": [ + "Send", + "Constructor", + "PubkeyAddress" + ], + "fil/2/cron": [ + "Send", + "Constructor", + "EpochTick" + ], + "fil/2/init": [ + "Send", + "Constructor", + "Exec" + ], + "fil/2/multisig": [ + "Send", + "Constructor", + "Propose", + "Approve", + "Cancel", + "AddSigner", + "RemoveSigner", + "SwapSigner", + "ChangeNumApprovalsThreshold", + "LockBalance" + ], + "fil/2/paymentchannel": [ + "Send", + "Constructor", + "UpdateChannelState", + "Settle", + "Collect" + ], + "fil/2/reward": [ + "Send", + "Constructor", + "AwardBlockReward", + "ThisEpochReward", + "UpdateNetworkKPI" + ], + "fil/2/storagemarket": [ + "Send", + "Constructor", + "AddBalance", + "WithdrawBalance", + "PublishStorageDeals", + "VerifyDealsForActivation", + "ActivateDeals", + "OnMinerSectorsTerminate", + "ComputeDataCommitment", + "CronTick" + ], + "fil/2/storageminer": [ + "Send", + "Constructor", + "ControlAddresses", + "ChangeWorkerAddress", + "ChangePeerID", + "SubmitWindowedPoSt", + "PreCommitSector", + "ProveCommitSector", + "ExtendSectorExpiration", + "TerminateSectors", + "DeclareFaults", + "DeclareFaultsRecovered", + "OnDeferredCronEvent", + "CheckSectorProven", + "ApplyRewards", + "ReportConsensusFault", + "WithdrawBalance", + "ConfirmSectorProofsValid", + "ChangeMultiaddrs", + "CompactPartitions", + "CompactSectorNumbers", + "ConfirmUpdateWorkerKey", + "RepayDebt" + ], + "fil/2/storagepower": [ + "Send", + "Constructor", + "CreateMiner", + "UpdateClaimedPower", + "EnrollCronEvent", + "OnEpochTickEnd", + "UpdatePledgeTotal", + "SubmitPoRepForBulkVerify", + "CurrentTotalPower" + ], + "fil/2/system": [ + "Send", + "Constructor" + ], + "fil/2/verifiedregistry": [ + "Send", + "Constructor", + "AddVerifier", + "RemoveVerifier", + "AddVerifiedClient", + "UseBytes", + "RestoreBytes" ] } \ No newline at end of file diff --git a/markets/retrievaladapter/client.go b/markets/retrievaladapter/client.go index ab81dd8c9..1bef23e12 100644 --- a/markets/retrievaladapter/client.go +++ b/markets/retrievaladapter/client.go @@ -3,8 +3,6 @@ package retrievaladapter import ( "context" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/shared" @@ -12,6 +10,7 @@ import ( "github.com/ipfs/go-cid" "github.com/multiformats/go-multiaddr" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/impl/full" payapi "github.com/filecoin-project/lotus/node/impl/paych" diff --git a/markets/retrievaladapter/provider.go b/markets/retrievaladapter/provider.go index 443c4fb4a..674ec4793 100644 --- a/markets/retrievaladapter/provider.go +++ b/markets/retrievaladapter/provider.go @@ -5,6 +5,7 @@ import ( "io" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/types" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" @@ -14,7 +15,6 @@ import ( "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/shared" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/ipfs/go-cid" ) diff --git a/node/builder.go b/node/builder.go index 41fb01ef7..0d48ec130 100644 --- a/node/builder.go +++ b/node/builder.go @@ -259,7 +259,8 @@ func Online() Option { Override(new(ffiwrapper.Verifier), ffiwrapper.ProofVerifier), Override(new(vm.SyscallBuilder), vm.Syscalls), Override(new(*store.ChainStore), modules.ChainStore), - Override(new(*stmgr.StateManager), stmgr.NewStateManager), + Override(new(stmgr.UpgradeSchedule), stmgr.DefaultUpgradeSchedule()), + Override(new(*stmgr.StateManager), stmgr.NewStateManagerWithUpgradeSchedule), Override(new(*wallet.Wallet), wallet.NewWallet), Override(new(*messagesigner.MessageSigner), messagesigner.NewMessageSigner), diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 5c1752154..f146dcea3 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -42,7 +42,6 @@ import ( "github.com/filecoin-project/go-multistore" "github.com/filecoin-project/go-padreader" "github.com/filecoin-project/go-state-types/abi" - miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" marketevents "github.com/filecoin-project/lotus/markets/loggers" @@ -88,7 +87,7 @@ func calcDealExpiration(minDuration uint64, md *dline.Info, startEpoch abi.Chain minExp := startEpoch + abi.ChainEpoch(minDuration) // Align on miners ProvingPeriodBoundary - return minExp + miner0.WPoStProvingPeriod - (minExp % miner0.WPoStProvingPeriod) + (md.PeriodStart % miner0.WPoStProvingPeriod) - 1 + return minExp + md.WPoStProvingPeriod - (minExp % md.WPoStProvingPeriod) + (md.PeriodStart % md.WPoStProvingPeriod) - 1 } func (a *API) imgr() *importmgr.Mgr { diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 9606a023a..095e32ad2 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -285,6 +285,8 @@ func (s stringKey) Key() string { return (string)(s) } +// TODO: ActorUpgrade: this entire function is a problem (in theory) as we don't know the HAMT version. +// In practice, hamt v0 should work "just fine" for reading. func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) { return func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) { store := adt.WrapStore(ctx, cbor.NewCborStore(bs)) @@ -422,7 +424,7 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod return nil, nil, xerrors.Errorf("getting actor head for @state: %w", err) } - m, err := vm.DumpActorState(act.Code, head.RawData()) + m, err := vm.DumpActorState(&act, head.RawData()) if err != nil { return nil, nil, err } diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index f03807c80..c912c7a8c 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -6,6 +6,8 @@ import ( "math/rand" "sort" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "go.uber.org/fx" "golang.org/x/xerrors" @@ -182,7 +184,7 @@ func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message, return res.MsgRct.GasUsed, nil } - if !act.IsPaymentChannelActor() { + if !builtin.IsPaymentChannelActor(act.Code) { return res.MsgRct.GasUsed, nil } if msgIn.Method != builtin0.MethodsPaych.Collect { diff --git a/node/impl/full/multisig.go b/node/impl/full/multisig.go index 8c15a27be..715689edc 100644 --- a/node/impl/full/multisig.go +++ b/node/impl/full/multisig.go @@ -9,15 +9,13 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" - init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" "github.com/filecoin-project/lotus/chain/types" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" - init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" "github.com/ipfs/go-cid" - "github.com/minio/blake2b-simd" "go.uber.org/fx" "golang.org/x/xerrors" ) @@ -30,58 +28,31 @@ type MsigAPI struct { MpoolAPI MpoolAPI } +func (a *MsigAPI) messageBuilder(ctx context.Context, from address.Address) (multisig.MessageBuilder, error) { + nver, err := a.StateAPI.StateNetworkVersion(ctx, types.EmptyTSK) + if err != nil { + return nil, err + } + + return multisig.Message(actors.VersionForNetwork(nver), from), nil +} + // TODO: remove gp (gasPrice) from arguments +// TODO: Add "vesting start" to arguments. func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) { - lenAddrs := uint64(len(addrs)) - - if lenAddrs < req { - return cid.Undef, xerrors.Errorf("cannot require signing of more addresses than provided for multisig") + mb, err := a.messageBuilder(ctx, src) + if err != nil { + return cid.Undef, err } - if req == 0 { - req = lenAddrs - } - - if src == address.Undef { - return cid.Undef, xerrors.Errorf("must provide source address") - } - - // Set up constructor parameters for multisig - msigParams := &multisig0.ConstructorParams{ - Signers: addrs, - NumApprovalsThreshold: req, - UnlockDuration: duration, - } - - enc, actErr := actors.SerializeParams(msigParams) - if actErr != nil { - return cid.Undef, actErr - } - - // new actors are created by invoking 'exec' on the init actor with the constructor params - // TODO: network upgrade? - execParams := &init0.ExecParams{ - CodeCID: builtin0.MultisigActorCodeID, - ConstructorParams: enc, - } - - enc, actErr = actors.SerializeParams(execParams) - if actErr != nil { - return cid.Undef, actErr - } - - // now we create the message to send this with - msg := types.Message{ - To: init_.Address, - From: src, - Method: builtin0.MethodsInit.Exec, - Params: enc, - Value: val, + msg, err := mb.Create(addrs, req, 0, duration, val) + if err != nil { + return cid.Undef, err } // send the message out to the network - smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, &msg, nil) + smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg, nil) if err != nil { return cid.Undef, err } @@ -91,38 +62,14 @@ func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Ad func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) { - if msig == address.Undef { - return cid.Undef, xerrors.Errorf("must provide a multisig address for proposal") + mb, err := a.messageBuilder(ctx, src) + if err != nil { + return cid.Undef, err } - if to == address.Undef { - return cid.Undef, xerrors.Errorf("must provide a target address for proposal") - } - - if amt.Sign() == -1 { - return cid.Undef, xerrors.Errorf("must provide a positive amount for proposed send") - } - - if src == address.Undef { - return cid.Undef, xerrors.Errorf("must provide source address") - } - - enc, actErr := actors.SerializeParams(&multisig0.ProposeParams{ - To: to, - Value: amt, - Method: abi.MethodNum(method), - Params: params, - }) - if actErr != nil { - return cid.Undef, xerrors.Errorf("failed to serialize parameters: %w", actErr) - } - - msg := &types.Message{ - To: msig, - From: src, - Value: types.NewInt(0), - Method: builtin0.MethodsMultisig.Propose, - Params: enc, + msg, err := mb.Propose(msig, to, amt, abi.MethodNum(method), params) + if err != nil { + return cid.Undef, xerrors.Errorf("failed to create proposal: %w", err) } smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg, nil) @@ -200,14 +147,6 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro return cid.Undef, xerrors.Errorf("must provide multisig address") } - if to == address.Undef { - return cid.Undef, xerrors.Errorf("must provide proposed target address") - } - - if amt.Sign() == -1 { - return cid.Undef, xerrors.Errorf("must provide the positive amount that was proposed") - } - if src == address.Undef { return cid.Undef, xerrors.Errorf("must provide source address") } @@ -220,7 +159,7 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro proposer = proposerID } - p := multisig0.ProposalHashData{ + p := multisig.ProposalHashData{ Requester: proposer, To: to, Value: amt, @@ -228,42 +167,22 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro Params: params, } - pser, err := p.Serialize() - if err != nil { - return cid.Undef, err - } - phash := blake2b.Sum256(pser) - - enc, err := actors.SerializeParams(&multisig0.TxnIDParams{ - ID: multisig0.TxnID(txID), - ProposalHash: phash[:], - }) - + mb, err := a.messageBuilder(ctx, src) if err != nil { return cid.Undef, err } - var msigResponseMethod abi.MethodNum - - /* - We pass in a MsigProposeResponse instead of MethodNum to - tighten the possible inputs to just Approve and Cancel. - */ + var msg *types.Message switch operation { case api.MsigApprove: - msigResponseMethod = builtin0.MethodsMultisig.Approve + msg, err = mb.Approve(msig, txID, &p) case api.MsigCancel: - msigResponseMethod = builtin0.MethodsMultisig.Cancel + msg, err = mb.Cancel(msig, txID, &p) default: return cid.Undef, xerrors.Errorf("Invalid operation for msigApproveOrCancel") } - - msg := &types.Message{ - To: msig, - From: src, - Value: types.NewInt(0), - Method: msigResponseMethod, - Params: enc, + if err != nil { + return cid.Undef, err } smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg, nil) diff --git a/node/impl/full/state.go b/node/impl/full/state.go index e5bd9f9d8..3a4390d03 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -5,10 +5,8 @@ import ( "context" "strconv" - lotusbuiltin "github.com/filecoin-project/lotus/chain/actors/builtin" - - builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" - market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/actors/builtin/verifreg" @@ -411,7 +409,7 @@ func (a *StateAPI) StateReadState(ctx context.Context, actor address.Address, ts return nil, xerrors.Errorf("getting actor head: %w", err) } - oif, err := vm.DumpActorState(act.Code, blk.RawData()) + oif, err := vm.DumpActorState(act, blk.RawData()) if err != nil { return nil, xerrors.Errorf("dumping actor state (a:%s): %w", actor, err) } @@ -883,10 +881,10 @@ func (a *StateAPI) StateMinerPreCommitDepositForPower(ctx context.Context, maddr } else { // NB: not exactly accurate, but should always lead us to *over* estimate, not under duration := pci.Expiration - ts.Height() - sectorWeight = lotusbuiltin.QAPowerForWeight(ssize, duration, w, vw) + sectorWeight = builtin.QAPowerForWeight(ssize, duration, w, vw) } - var powerSmoothed lotusbuiltin.FilterEstimate + var powerSmoothed builtin.FilterEstimate if act, err := state.GetActor(power.Address); err != nil { return types.EmptyInt, xerrors.Errorf("loading power actor: %w", err) } else if s, err := power.Load(store, act); err != nil { @@ -944,11 +942,11 @@ func (a *StateAPI) StateMinerInitialPledgeCollateral(ctx context.Context, maddr } else { // NB: not exactly accurate, but should always lead us to *over* estimate, not under duration := pci.Expiration - ts.Height() - sectorWeight = lotusbuiltin.QAPowerForWeight(ssize, duration, w, vw) + sectorWeight = builtin.QAPowerForWeight(ssize, duration, w, vw) } var ( - powerSmoothed lotusbuiltin.FilterEstimate + powerSmoothed builtin.FilterEstimate pledgeCollateral abi.TokenAmount ) if act, err := state.GetActor(power.Address); err != nil { @@ -1108,12 +1106,12 @@ func (a *StateAPI) StateDealProviderCollateralBounds(ctx context.Context, size a return api.DealCollateralBounds{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - pact, err := a.StateGetActor(ctx, builtin0.StoragePowerActorAddr, tsk) + pact, err := a.StateGetActor(ctx, power.Address, tsk) if err != nil { return api.DealCollateralBounds{}, xerrors.Errorf("failed to load power actor: %w", err) } - ract, err := a.StateGetActor(ctx, builtin0.RewardActorAddr, tsk) + ract, err := a.StateGetActor(ctx, reward.Address, tsk) if err != nil { return api.DealCollateralBounds{}, xerrors.Errorf("failed to load reward actor: %w", err) } @@ -1143,7 +1141,7 @@ func (a *StateAPI) StateDealProviderCollateralBounds(ctx context.Context, size a return api.DealCollateralBounds{}, xerrors.Errorf("getting reward baseline power: %w", err) } - min, max := market0.DealProviderCollateralBounds(size, + min, max := policy.DealProviderCollateralBounds(size, verified, powClaim.RawBytePower, powClaim.QualityAdjPower, diff --git a/node/test/builder.go b/node/test/builder.go index c496b1e4c..a3455f376 100644 --- a/node/test/builder.go +++ b/node/test/builder.go @@ -137,7 +137,7 @@ func CreateTestStorageNode(ctx context.Context, t *testing.T, waddr address.Addr return test.TestStorageNode{StorageMiner: minerapi, MineOne: mineOne} } -func Builder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) { +func Builder(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) { ctx := context.Background() mn := mocknet.New(ctx) @@ -198,6 +198,7 @@ func Builder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestN templ := &genesis.Template{ Accounts: genaccs, Miners: genms, + NetworkName: "test", Timestamp: uint64(time.Now().Unix() - 10000), // some time sufficiently far in the past VerifregRootKey: gen.DefaultVerifregRootkeyActor, RemainderAccount: gen.DefaultRemainderAccountActor, @@ -223,6 +224,7 @@ func Builder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestN node.Test(), genesis, + node.Options(opts...), ) if err != nil { t.Fatal(err) @@ -284,7 +286,7 @@ func Builder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestN return fulls, storers } -func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) { +func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner, options ...node.Option) ([]test.TestNode, []test.TestStorageNode) { ctx := context.Background() mn := mocknet.New(ctx) @@ -344,6 +346,7 @@ func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test templ := &genesis.Template{ Accounts: genaccs, Miners: genms, + NetworkName: "test", Timestamp: uint64(time.Now().Unix()) - (build.BlockDelaySecs * 20000), VerifregRootKey: gen.DefaultVerifregRootkeyActor, RemainderAccount: gen.DefaultRemainderAccountActor, @@ -371,6 +374,7 @@ func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), genesis, + node.Options(options...), ) if err != nil { t.Fatalf("%+v", err) @@ -433,16 +437,16 @@ func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test return fulls, storers } -func RPCBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) { - return rpcWithBuilder(t, Builder, nFull, storage) +func RPCBuilder(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) { + return rpcWithBuilder(t, Builder, nFull, storage, opts...) } -func RPCMockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) { - return rpcWithBuilder(t, MockSbBuilder, nFull, storage) +func RPCMockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) { + return rpcWithBuilder(t, MockSbBuilder, nFull, storage, opts...) } -func rpcWithBuilder(t *testing.T, b test.APIBuilder, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) { - fullApis, storaApis := b(t, nFull, storage) +func rpcWithBuilder(t *testing.T, b test.APIBuilder, nFull int, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) { + fullApis, storaApis := b(t, nFull, storage, opts...) fulls := make([]test.TestNode, nFull) storers := make([]test.TestStorageNode, len(storage)) diff --git a/paychmgr/manager.go b/paychmgr/manager.go index d9c568cbe..f2fc190c7 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -2,6 +2,7 @@ package paychmgr import ( "context" + "errors" "sync" "github.com/ipfs/go-cid" @@ -12,7 +13,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/crypto" - paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors/adt" @@ -25,6 +26,8 @@ import ( var log = logging.Logger("paych") +var errProofNotSupported = errors.New("payment channel proof parameter is not supported") + // PaychAPI is used by dependency injection to pass the consituent APIs to NewManager() type PaychAPI struct { fx.In @@ -47,6 +50,7 @@ type paychAPI interface { MpoolPushMessage(ctx context.Context, msg *types.Message, maxFee *api.MessageSendSpec) (*types.SignedMessage, error) WalletHas(ctx context.Context, addr address.Address) (bool, error) WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error) + StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) } // managerAPI defines all methods needed by the manager @@ -221,7 +225,7 @@ func (pm *Manager) GetChannelInfo(addr address.Address) (*ChannelInfo, error) { return ca.getChannelInfo(addr) } -func (pm *Manager) CreateVoucher(ctx context.Context, ch address.Address, voucher paych0.SignedVoucher) (*api.VoucherCreateResult, error) { +func (pm *Manager) CreateVoucher(ctx context.Context, ch address.Address, voucher paych.SignedVoucher) (*api.VoucherCreateResult, error) { ca, err := pm.accessorByAddress(ch) if err != nil { return nil, err @@ -233,7 +237,7 @@ func (pm *Manager) CreateVoucher(ctx context.Context, ch address.Address, vouche // CheckVoucherValid checks if the given voucher is valid (is or could become spendable at some point). // If the channel is not in the store, fetches the channel from state (and checks that // the channel To address is owned by the wallet). -func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher) error { +func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) error { // Get an accessor for the channel, creating it from state if necessary ca, err := pm.inboundChannelAccessor(ctx, ch) if err != nil { @@ -245,35 +249,44 @@ func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv } // CheckVoucherSpendable checks if the given voucher is currently spendable -func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, secret []byte, proof []byte) (bool, error) { +func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (bool, error) { + if len(proof) > 0 { + return false, errProofNotSupported + } ca, err := pm.accessorByAddress(ch) if err != nil { return false, err } - return ca.checkVoucherSpendable(ctx, ch, sv, secret, proof) + return ca.checkVoucherSpendable(ctx, ch, sv, secret) } // AddVoucherOutbound adds a voucher for an outbound channel. // Returns an error if the channel is not already in the store. -func (pm *Manager) AddVoucherOutbound(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { +func (pm *Manager) AddVoucherOutbound(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { + if len(proof) > 0 { + return types.NewInt(0), errProofNotSupported + } ca, err := pm.accessorByAddress(ch) if err != nil { return types.NewInt(0), err } - return ca.addVoucher(ctx, ch, sv, proof, minDelta) + return ca.addVoucher(ctx, ch, sv, minDelta) } // AddVoucherInbound adds a voucher for an inbound channel. // If the channel is not in the store, fetches the channel from state (and checks that // the channel To address is owned by the wallet). -func (pm *Manager) AddVoucherInbound(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { +func (pm *Manager) AddVoucherInbound(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { + if len(proof) > 0 { + return types.NewInt(0), errProofNotSupported + } // Get an accessor for the channel, creating it from state if necessary ca, err := pm.inboundChannelAccessor(ctx, ch) if err != nil { return types.BigInt{}, err } - return ca.addVoucher(ctx, ch, sv, proof, minDelta) + return ca.addVoucher(ctx, ch, sv, minDelta) } // inboundChannelAccessor gets an accessor for the given channel. The channel @@ -336,12 +349,15 @@ func (pm *Manager) trackInboundChannel(ctx context.Context, ch address.Address) return pm.store.TrackChannel(stateCi) } -func (pm *Manager) SubmitVoucher(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) { +func (pm *Manager) SubmitVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) { + if len(proof) > 0 { + return cid.Undef, errProofNotSupported + } ca, err := pm.accessorByAddress(ch) if err != nil { return cid.Undef, err } - return ca.submitVoucher(ctx, ch, sv, secret, proof) + return ca.submitVoucher(ctx, ch, sv, secret) } func (pm *Manager) AllocateLane(ch address.Address) (uint64, error) { diff --git a/paychmgr/mock_test.go b/paychmgr/mock_test.go index c761221d2..3393a3072 100644 --- a/paychmgr/mock_test.go +++ b/paychmgr/mock_test.go @@ -9,8 +9,10 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/sigs" @@ -241,3 +243,7 @@ func (pchapi *mockPaychAPI) addSigningKey(key []byte) { pchapi.signingKey = key } + +func (pchapi *mockPaychAPI) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) { + return build.NewestNetworkVersion, nil +} diff --git a/paychmgr/paych.go b/paychmgr/paych.go index e67991911..c4ef3deb0 100644 --- a/paychmgr/paych.go +++ b/paychmgr/paych.go @@ -1,7 +1,6 @@ package paychmgr import ( - "bytes" "context" "fmt" @@ -11,8 +10,6 @@ import ( "github.com/filecoin-project/go-address" cborutil "github.com/filecoin-project/go-cbor-util" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" @@ -85,6 +82,15 @@ func newChannelAccessor(pm *Manager, from address.Address, to address.Address) * } } +func (ca *channelAccessor) messageBuilder(ctx context.Context, from address.Address) (paych.MessageBuilder, error) { + nwVersion, err := ca.api.StateNetworkVersion(ctx, types.EmptyTSK) + if err != nil { + return nil, err + } + + return paych.Message(actors.VersionForNetwork(nwVersion), from), nil +} + func (ca *channelAccessor) getChannelInfo(addr address.Address) (*ChannelInfo, error) { ca.lk.Lock() defer ca.lk.Unlock() @@ -103,7 +109,7 @@ func (ca *channelAccessor) outboundActiveByFromTo(from, to address.Address) (*Ch // nonce, signing the voucher and storing it in the local datastore. // If there are not enough funds in the channel to create the voucher, returns // the shortfall in funds. -func (ca *channelAccessor) createVoucher(ctx context.Context, ch address.Address, voucher paych0.SignedVoucher) (*api.VoucherCreateResult, error) { +func (ca *channelAccessor) createVoucher(ctx context.Context, ch address.Address, voucher paych.SignedVoucher) (*api.VoucherCreateResult, error) { ca.lk.Lock() defer ca.lk.Unlock() @@ -133,7 +139,7 @@ func (ca *channelAccessor) createVoucher(ctx context.Context, ch address.Address sv.Signature = sig // Store the voucher - if _, err := ca.addVoucherUnlocked(ctx, ch, sv, nil, types.NewInt(0)); err != nil { + if _, err := ca.addVoucherUnlocked(ctx, ch, sv, types.NewInt(0)); err != nil { // If there are not enough funds in the channel to cover the voucher, // return a voucher create result with the shortfall var ife insufficientFundsErr @@ -162,14 +168,14 @@ func (ca *channelAccessor) nextNonceForLane(ci *ChannelInfo, lane uint64) uint64 return maxnonce + 1 } -func (ca *channelAccessor) checkVoucherValid(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher) (map[uint64]paych.LaneState, error) { +func (ca *channelAccessor) checkVoucherValid(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) (map[uint64]paych.LaneState, error) { ca.lk.Lock() defer ca.lk.Unlock() return ca.checkVoucherValidUnlocked(ctx, ch, sv) } -func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher) (map[uint64]paych.LaneState, error) { +func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) (map[uint64]paych.LaneState, error) { if sv.ChannelAddr != ch { return nil, xerrors.Errorf("voucher ChannelAddr doesn't match channel address, got %s, expected %s", sv.ChannelAddr, ch) } @@ -265,7 +271,7 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add return laneStates, nil } -func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, secret []byte, proof []byte) (bool, error) { +func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte) (bool, error) { ca.lk.Lock() defer ca.lk.Unlock() @@ -288,37 +294,17 @@ func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address return false, nil } - // If proof is needed and wasn't supplied as a parameter, get it from the - // datastore - if sv.Extra != nil && proof == nil { - vi, err := ci.infoForVoucher(sv) - if err != nil { - return false, err - } - - if vi.Proof != nil { - log.Info("CheckVoucherSpendable: using stored proof") - proof = vi.Proof - } else { - log.Warn("CheckVoucherSpendable: nil proof for voucher with validation") - } - } - - enc, err := actors.SerializeParams(&paych0.UpdateChannelStateParams{ - Sv: *sv, - Secret: secret, - Proof: proof, - }) + mb, err := ca.messageBuilder(ctx, recipient) if err != nil { return false, err } - ret, err := ca.api.Call(ctx, &types.Message{ - From: recipient, - To: ch, - Method: builtin.MethodsPaych.UpdateChannelState, - Params: enc, - }, nil) + mes, err := mb.Update(ch, sv, secret) + if err != nil { + return false, err + } + + ret, err := ca.api.Call(ctx, mes, nil) if err != nil { return false, err } @@ -339,44 +325,31 @@ func (ca *channelAccessor) getPaychRecipient(ctx context.Context, ch address.Add return state.To() } -func (ca *channelAccessor) addVoucher(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { +func (ca *channelAccessor) addVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, minDelta types.BigInt) (types.BigInt, error) { ca.lk.Lock() defer ca.lk.Unlock() - return ca.addVoucherUnlocked(ctx, ch, sv, proof, minDelta) + return ca.addVoucherUnlocked(ctx, ch, sv, minDelta) } -func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { +func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, minDelta types.BigInt) (types.BigInt, error) { ci, err := ca.store.ByAddress(ch) if err != nil { return types.BigInt{}, err } // Check if the voucher has already been added - for i, v := range ci.Vouchers { + for _, v := range ci.Vouchers { eq, err := cborutil.Equals(sv, v.Voucher) if err != nil { return types.BigInt{}, err } - if !eq { - continue + if eq { + // Ignore the duplicate voucher. + log.Warnf("AddVoucher: voucher re-added") + return types.NewInt(0), nil } - // This is a duplicate voucher. - // Update the proof on the existing voucher - if len(proof) > 0 && !bytes.Equal(v.Proof, proof) { - log.Warnf("AddVoucher: adding proof to stored voucher") - ci.Vouchers[i] = &VoucherInfo{ - Voucher: v.Voucher, - Proof: proof, - } - - return types.NewInt(0), ca.store.putChannelInfo(ci) - } - - // Otherwise just ignore the duplicate voucher - log.Warnf("AddVoucher: voucher re-added with matching proof") - return types.NewInt(0), nil } // Check voucher validity @@ -403,7 +376,6 @@ func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Ad ci.Vouchers = append(ci.Vouchers, &VoucherInfo{ Voucher: sv, - Proof: proof, }) if ci.NextLane <= sv.Lane { @@ -413,7 +385,7 @@ func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Ad return delta, ca.store.putChannelInfo(ci) } -func (ca *channelAccessor) submitVoucher(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) { +func (ca *channelAccessor) submitVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte) (cid.Cid, error) { ca.lk.Lock() defer ca.lk.Unlock() @@ -422,21 +394,6 @@ func (ca *channelAccessor) submitVoucher(ctx context.Context, ch address.Address return cid.Undef, err } - // If voucher needs proof, and none was supplied, check datastore for proof - if sv.Extra != nil && proof == nil { - vi, err := ci.infoForVoucher(sv) - if err != nil { - return cid.Undef, err - } - - if vi.Proof != nil { - log.Info("SubmitVoucher: using stored proof") - proof = vi.Proof - } else { - log.Warn("SubmitVoucher: nil proof for voucher with validation") - } - } - has, err := ci.hasVoucher(sv) if err != nil { return cid.Undef, err @@ -454,21 +411,14 @@ func (ca *channelAccessor) submitVoucher(ctx context.Context, ch address.Address } } - enc, err := actors.SerializeParams(&paych0.UpdateChannelStateParams{ - Sv: *sv, - Secret: secret, - Proof: proof, - }) + mb, err := ca.messageBuilder(ctx, ci.Control) if err != nil { return cid.Undef, err } - msg := &types.Message{ - From: ci.Control, - To: ch, - Value: types.NewInt(0), - Method: builtin.MethodsPaych.UpdateChannelState, - Params: enc, + msg, err := mb.Update(ch, sv, secret) + if err != nil { + return cid.Undef, err } smsg, err := ca.api.MpoolPushMessage(ctx, msg, nil) @@ -481,7 +431,6 @@ func (ca *channelAccessor) submitVoucher(ctx context.Context, ch address.Address // Add the voucher to the channel ci.Vouchers = append(ci.Vouchers, &VoucherInfo{ Voucher: sv, - Proof: proof, }) } @@ -568,7 +517,7 @@ func (ca *channelAccessor) laneState(state paych.State, ch address.Address) (map } // Get the total redeemed amount across all lanes, after applying the voucher -func (ca *channelAccessor) totalRedeemedWithVoucher(laneStates map[uint64]paych.LaneState, sv *paych0.SignedVoucher) (big.Int, error) { +func (ca *channelAccessor) totalRedeemedWithVoucher(laneStates map[uint64]paych.LaneState, sv *paych.SignedVoucher) (big.Int, error) { // TODO: merges if len(sv.Merges) != 0 { return big.Int{}, xerrors.Errorf("dont currently support paych lane merges") @@ -621,11 +570,13 @@ func (ca *channelAccessor) settle(ctx context.Context, ch address.Address) (cid. return cid.Undef, err } - msg := &types.Message{ - To: ch, - From: ci.Control, - Value: types.NewInt(0), - Method: builtin.MethodsPaych.Settle, + mb, err := ca.messageBuilder(ctx, ci.Control) + if err != nil { + return cid.Undef, err + } + msg, err := mb.Settle(ch) + if err != nil { + return cid.Undef, err } smgs, err := ca.api.MpoolPushMessage(ctx, msg, nil) if err != nil { @@ -650,11 +601,14 @@ func (ca *channelAccessor) collect(ctx context.Context, ch address.Address) (cid return cid.Undef, err } - msg := &types.Message{ - To: ch, - From: ci.Control, - Value: types.NewInt(0), - Method: builtin.MethodsPaych.Collect, + mb, err := ca.messageBuilder(ctx, ci.Control) + if err != nil { + return cid.Undef, err + } + + msg, err := mb.Collect(ch) + if err != nil { + return cid.Undef, err } smsg, err := ca.api.MpoolPushMessage(ctx, msg, nil) diff --git a/paychmgr/paych_test.go b/paychmgr/paych_test.go index 56e7e9089..fcd3d50a8 100644 --- a/paychmgr/paych_test.go +++ b/paychmgr/paych_test.go @@ -15,8 +15,8 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/builtin" - paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" tutils "github.com/filecoin-project/specs-actors/support/testing" + paych2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/paych" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors/builtin/paych" @@ -237,7 +237,7 @@ func TestCreateVoucher(t *testing.T) { // Create a voucher in lane 1 voucherLane1Amt := big.NewInt(5) - voucher := paych0.SignedVoucher{ + voucher := paych2.SignedVoucher{ Lane: 1, Amount: voucherLane1Amt, } @@ -252,7 +252,7 @@ func TestCreateVoucher(t *testing.T) { // Create a voucher in lane 1 again, with a higher amount voucherLane1Amt = big.NewInt(8) - voucher = paych0.SignedVoucher{ + voucher = paych2.SignedVoucher{ Lane: 1, Amount: voucherLane1Amt, } @@ -267,7 +267,7 @@ func TestCreateVoucher(t *testing.T) { // Create a voucher in lane 2 that covers all the remaining funds // in the channel voucherLane2Amt := big.Sub(s.amt, voucherLane1Amt) - voucher = paych0.SignedVoucher{ + voucher = paych2.SignedVoucher{ Lane: 2, Amount: voucherLane2Amt, } @@ -281,7 +281,7 @@ func TestCreateVoucher(t *testing.T) { // Create a voucher in lane 2 that exceeds the remaining funds in the // channel voucherLane2Amt = big.Add(voucherLane2Amt, big.NewInt(1)) - voucher = paych0.SignedVoucher{ + voucher = paych2.SignedVoucher{ Lane: 2, Amount: voucherLane2Amt, } @@ -450,53 +450,6 @@ func TestAllocateLaneWithExistingLaneState(t *testing.T) { require.EqualValues(t, 3, lane) } -func TestAddVoucherProof(t *testing.T) { - ctx := context.Background() - - // Set up a manager with a single payment channel - s := testSetupMgrWithChannel(t) - - nonce := uint64(1) - voucherAmount := big.NewInt(1) - minDelta := big.NewInt(0) - voucherAmount = big.NewInt(2) - voucherLane := uint64(1) - - // Add a voucher with no proof - var proof []byte - sv := createTestVoucher(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate) - _, err := s.mgr.AddVoucherOutbound(ctx, s.ch, sv, nil, minDelta) - require.NoError(t, err) - - // Expect one voucher with no proof - ci, err := s.mgr.GetChannelInfo(s.ch) - require.NoError(t, err) - require.Len(t, ci.Vouchers, 1) - require.Len(t, ci.Vouchers[0].Proof, 0) - - // Add same voucher with no proof - voucherLane = uint64(1) - _, err = s.mgr.AddVoucherOutbound(ctx, s.ch, sv, proof, minDelta) - require.NoError(t, err) - - // Expect one voucher with no proof - ci, err = s.mgr.GetChannelInfo(s.ch) - require.NoError(t, err) - require.Len(t, ci.Vouchers, 1) - require.Len(t, ci.Vouchers[0].Proof, 0) - - // Add same voucher with proof - proof = []byte{1} - _, err = s.mgr.AddVoucherOutbound(ctx, s.ch, sv, proof, minDelta) - require.NoError(t, err) - - // Should add proof to existing voucher - ci, err = s.mgr.GetChannelInfo(s.ch) - require.NoError(t, err) - require.Len(t, ci.Vouchers, 1) - require.Len(t, ci.Vouchers[0].Proof, 1) -} - func TestAddVoucherInboundWalletKey(t *testing.T) { ctx := context.Background() @@ -644,10 +597,9 @@ func TestCheckSpendable(t *testing.T) { voucherAmount := big.NewInt(1) voucher := createTestVoucherWithExtra(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate) - // Add voucher with proof + // Add voucher minDelta := big.NewInt(0) - proof := []byte("proof") - _, err := s.mgr.AddVoucherInbound(ctx, s.ch, voucher, proof, minDelta) + _, err := s.mgr.AddVoucherInbound(ctx, s.ch, voucher, nil, minDelta) require.NoError(t, err) // Return success exit code from VM call, which indicates that voucher is @@ -661,33 +613,17 @@ func TestCheckSpendable(t *testing.T) { // Check that spendable is true secret := []byte("secret") - otherProof := []byte("other proof") - spendable, err := s.mgr.CheckVoucherSpendable(ctx, s.ch, voucher, secret, otherProof) + spendable, err := s.mgr.CheckVoucherSpendable(ctx, s.ch, voucher, secret, nil) require.NoError(t, err) require.True(t, spendable) - // Check that the secret and proof were passed through correctly + // Check that the secret was passed through correctly lastCall := s.mock.getLastCall() - var p paych0.UpdateChannelStateParams + var p paych2.UpdateChannelStateParams err = p.UnmarshalCBOR(bytes.NewReader(lastCall.Params)) require.NoError(t, err) - require.Equal(t, otherProof, p.Proof) require.Equal(t, secret, p.Secret) - // Check that if no proof is supplied, the proof supplied to add voucher - // above is used - secret2 := []byte("secret2") - spendable, err = s.mgr.CheckVoucherSpendable(ctx, s.ch, voucher, secret2, nil) - require.NoError(t, err) - require.True(t, spendable) - - lastCall = s.mock.getLastCall() - var p2 paych0.UpdateChannelStateParams - err = p2.UnmarshalCBOR(bytes.NewReader(lastCall.Params)) - require.NoError(t, err) - require.Equal(t, proof, p2.Proof) - require.Equal(t, secret2, p2.Secret) - // Check that if VM call returns non-success exit code, spendable is false s.mock.setCallResponse(&api.InvocResult{ MsgRct: &types.MessageReceipt{ @@ -725,73 +661,48 @@ func TestSubmitVoucher(t *testing.T) { voucherAmount := big.NewInt(1) voucher := createTestVoucherWithExtra(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate) - // Add voucher with proof + // Add voucher minDelta := big.NewInt(0) - addVoucherProof := []byte("proof") - _, err := s.mgr.AddVoucherInbound(ctx, s.ch, voucher, addVoucherProof, minDelta) + _, err := s.mgr.AddVoucherInbound(ctx, s.ch, voucher, nil, minDelta) require.NoError(t, err) // Submit voucher secret := []byte("secret") - submitProof := []byte("submit proof") - submitCid, err := s.mgr.SubmitVoucher(ctx, s.ch, voucher, secret, submitProof) + submitCid, err := s.mgr.SubmitVoucher(ctx, s.ch, voucher, secret, nil) require.NoError(t, err) - // Check that the secret and proof were passed through correctly + // Check that the secret was passed through correctly msg := s.mock.pushedMessages(submitCid) - var p paych0.UpdateChannelStateParams + var p paych2.UpdateChannelStateParams err = p.UnmarshalCBOR(bytes.NewReader(msg.Message.Params)) require.NoError(t, err) - require.Equal(t, submitProof, p.Proof) require.Equal(t, secret, p.Secret) - // Check that if no proof is supplied to submit voucher, the proof supplied - // to add voucher is used - nonce++ - voucherAmount = big.NewInt(2) - addVoucherProof2 := []byte("proof2") - secret2 := []byte("secret2") - voucher = createTestVoucherWithExtra(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate) - _, err = s.mgr.AddVoucherInbound(ctx, s.ch, voucher, addVoucherProof2, minDelta) - require.NoError(t, err) - - submitCid, err = s.mgr.SubmitVoucher(ctx, s.ch, voucher, secret2, nil) - require.NoError(t, err) - - msg = s.mock.pushedMessages(submitCid) - var p2 paych0.UpdateChannelStateParams - err = p2.UnmarshalCBOR(bytes.NewReader(msg.Message.Params)) - require.NoError(t, err) - require.Equal(t, addVoucherProof2, p2.Proof) - require.Equal(t, secret2, p2.Secret) - // Submit a voucher without first adding it nonce++ voucherAmount = big.NewInt(3) secret3 := []byte("secret2") - proof3 := []byte("proof3") voucher = createTestVoucherWithExtra(t, s.ch, voucherLane, nonce, voucherAmount, s.fromKeyPrivate) - submitCid, err = s.mgr.SubmitVoucher(ctx, s.ch, voucher, secret3, proof3) + submitCid, err = s.mgr.SubmitVoucher(ctx, s.ch, voucher, secret3, nil) require.NoError(t, err) msg = s.mock.pushedMessages(submitCid) - var p3 paych0.UpdateChannelStateParams + var p3 paych2.UpdateChannelStateParams err = p3.UnmarshalCBOR(bytes.NewReader(msg.Message.Params)) require.NoError(t, err) - require.Equal(t, proof3, p3.Proof) require.Equal(t, secret3, p3.Secret) // Verify that vouchers are marked as submitted vis, err := s.mgr.ListVouchers(ctx, s.ch) require.NoError(t, err) - require.Len(t, vis, 3) + require.Len(t, vis, 2) for _, vi := range vis { require.True(t, vi.Submitted) } // Attempting to submit the same voucher again should fail - _, err = s.mgr.SubmitVoucher(ctx, s.ch, voucher, secret2, nil) + _, err = s.mgr.SubmitVoucher(ctx, s.ch, voucher, secret3, nil) require.Error(t, err) } @@ -862,8 +773,8 @@ func testGenerateKeyPair(t *testing.T) ([]byte, []byte) { return priv, pub } -func createTestVoucher(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych0.SignedVoucher { - sv := &paych0.SignedVoucher{ +func createTestVoucher(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych2.SignedVoucher { + sv := &paych2.SignedVoucher{ ChannelAddr: ch, Lane: voucherLane, Nonce: nonce, @@ -878,13 +789,13 @@ func createTestVoucher(t *testing.T, ch address.Address, voucherLane uint64, non return sv } -func createTestVoucherWithExtra(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych0.SignedVoucher { - sv := &paych0.SignedVoucher{ +func createTestVoucherWithExtra(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych2.SignedVoucher { + sv := &paych2.SignedVoucher{ ChannelAddr: ch, Lane: voucherLane, Nonce: nonce, Amount: voucherAmount, - Extra: &paych0.ModVerifyParams{ + Extra: &paych2.ModVerifyParams{ Actor: tutils.NewActorAddr(t, "act"), }, } @@ -902,13 +813,13 @@ type mockBestSpendableAPI struct { mgr *Manager } -func (m *mockBestSpendableAPI) PaychVoucherList(ctx context.Context, ch address.Address) ([]*paych0.SignedVoucher, error) { +func (m *mockBestSpendableAPI) PaychVoucherList(ctx context.Context, ch address.Address) ([]*paych2.SignedVoucher, error) { vi, err := m.mgr.ListVouchers(ctx, ch) if err != nil { return nil, err } - out := make([]*paych0.SignedVoucher, len(vi)) + out := make([]*paych2.SignedVoucher, len(vi)) for k, v := range vi { out[k] = v.Voucher } @@ -916,7 +827,7 @@ func (m *mockBestSpendableAPI) PaychVoucherList(ctx context.Context, ch address. return out, nil } -func (m *mockBestSpendableAPI) PaychVoucherCheckSpendable(ctx context.Context, ch address.Address, voucher *paych0.SignedVoucher, secret []byte, proof []byte) (bool, error) { +func (m *mockBestSpendableAPI) PaychVoucherCheckSpendable(ctx context.Context, ch address.Address, voucher *paych2.SignedVoucher, secret []byte, proof []byte) (bool, error) { return m.mgr.CheckVoucherSpendable(ctx, ch, voucher, secret, proof) } diff --git a/paychmgr/paychget_test.go b/paychmgr/paychget_test.go index e35ae8371..9f19dd13d 100644 --- a/paychmgr/paychget_test.go +++ b/paychmgr/paychget_test.go @@ -15,9 +15,9 @@ 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/specs-actors/actors/builtin" - init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - tutils "github.com/filecoin-project/specs-actors/support/testing" + "github.com/filecoin-project/specs-actors/v2/actors/builtin" + init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" + tutils "github.com/filecoin-project/specs-actors/v2/support/testing" lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init" "github.com/filecoin-project/lotus/chain/actors/builtin/paych" @@ -26,7 +26,7 @@ import ( ) func testChannelResponse(t *testing.T, ch address.Address) types.MessageReceipt { - createChannelRet := init_.ExecReturn{ + createChannelRet := init2.ExecReturn{ IDAddress: ch, RobustAddress: ch, } diff --git a/paychmgr/settler/settler.go b/paychmgr/settler/settler.go index 654ed66cc..02fe9256e 100644 --- a/paychmgr/settler/settler.go +++ b/paychmgr/settler/settler.go @@ -15,10 +15,10 @@ import ( "github.com/filecoin-project/go-state-types/abi" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" - paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/impl/full" @@ -39,9 +39,9 @@ type API struct { type settlerAPI interface { PaychList(context.Context) ([]address.Address, error) PaychStatus(context.Context, address.Address) (*api.PaychStatus, error) - PaychVoucherCheckSpendable(context.Context, address.Address, *paych0.SignedVoucher, []byte, []byte) (bool, error) - PaychVoucherList(context.Context, address.Address) ([]*paych0.SignedVoucher, error) - PaychVoucherSubmit(context.Context, address.Address, *paych0.SignedVoucher, []byte, []byte) (cid.Cid, error) + PaychVoucherCheckSpendable(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) + PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error) + PaychVoucherSubmit(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) } @@ -86,7 +86,7 @@ func (pcs *paymentChannelSettler) messageHandler(msg *types.Message, rec *types. if err != nil { return true, err } - go func(voucher *paych0.SignedVoucher, submitMessageCID cid.Cid) { + go func(voucher *paych.SignedVoucher, submitMessageCID cid.Cid) { defer wg.Done() msgLookup, err := pcs.api.StateWaitMsg(pcs.ctx, submitMessageCID, build.MessageConfidence) if err != nil { diff --git a/paychmgr/simple.go b/paychmgr/simple.go index ca778829f..253075604 100644 --- a/paychmgr/simple.go +++ b/paychmgr/simple.go @@ -12,14 +12,11 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" - paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + + init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/actors" - lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init" "github.com/filecoin-project/lotus/chain/types" ) @@ -387,25 +384,13 @@ func (ca *channelAccessor) processTask(ctx context.Context, amt types.BigInt) *p // createPaych sends a message to create the channel and returns the message cid func (ca *channelAccessor) createPaych(ctx context.Context, amt types.BigInt) (cid.Cid, error) { - params, aerr := actors.SerializeParams(&paych0.ConstructorParams{From: ca.from, To: ca.to}) - if aerr != nil { - return cid.Undef, aerr + mb, err := ca.messageBuilder(ctx, ca.from) + if err != nil { + return cid.Undef, err } - - enc, aerr := actors.SerializeParams(&init0.ExecParams{ - CodeCID: builtin.PaymentChannelActorCodeID, - ConstructorParams: params, - }) - if aerr != nil { - return cid.Undef, aerr - } - - msg := &types.Message{ - To: lotusinit.Address, - From: ca.from, - Value: amt, - Method: builtin.MethodsInit.Exec, - Params: enc, + msg, err := mb.Create(ca.to, amt) + if err != nil { + return cid.Undef, err } smsg, err := ca.api.MpoolPushMessage(ctx, msg, nil) @@ -457,7 +442,10 @@ func (ca *channelAccessor) waitPaychCreateMsg(channelID string, mcid cid.Cid) er return err } - var decodedReturn init0.ExecReturn + // TODO: ActorUpgrade abstract over this. + // This "works" because it hasn't changed from v0 to v2, but we still + // need an abstraction here. + var decodedReturn init2.ExecReturn err = decodedReturn.UnmarshalCBOR(bytes.NewReader(mwait.Receipt.Return)) if err != nil { log.Error(err) diff --git a/paychmgr/store.go b/paychmgr/store.go index 23916669e..a17ad1fcd 100644 --- a/paychmgr/store.go +++ b/paychmgr/store.go @@ -17,11 +17,10 @@ import ( "github.com/ipfs/go-datastore/namespace" dsq "github.com/ipfs/go-datastore/query" - paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" - "github.com/filecoin-project/go-address" cborrpc "github.com/filecoin-project/go-cbor-util" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -49,8 +48,8 @@ const ( ) type VoucherInfo struct { - Voucher *paych0.SignedVoucher - Proof []byte + Voucher *paych.SignedVoucher + Proof []byte // ignored Submitted bool } @@ -103,7 +102,7 @@ func (ci *ChannelInfo) to() address.Address { // infoForVoucher gets the VoucherInfo for the given voucher. // returns nil if the channel doesn't have the voucher. -func (ci *ChannelInfo) infoForVoucher(sv *paych0.SignedVoucher) (*VoucherInfo, error) { +func (ci *ChannelInfo) infoForVoucher(sv *paych.SignedVoucher) (*VoucherInfo, error) { for _, v := range ci.Vouchers { eq, err := cborutil.Equals(sv, v.Voucher) if err != nil { @@ -116,7 +115,7 @@ func (ci *ChannelInfo) infoForVoucher(sv *paych0.SignedVoucher) (*VoucherInfo, e return nil, nil } -func (ci *ChannelInfo) hasVoucher(sv *paych0.SignedVoucher) (bool, error) { +func (ci *ChannelInfo) hasVoucher(sv *paych.SignedVoucher) (bool, error) { vi, err := ci.infoForVoucher(sv) return vi != nil, err } @@ -124,7 +123,7 @@ func (ci *ChannelInfo) hasVoucher(sv *paych0.SignedVoucher) (bool, error) { // markVoucherSubmitted marks the voucher, and any vouchers of lower nonce // in the same lane, as being submitted. // Note: This method doesn't write anything to the store. -func (ci *ChannelInfo) markVoucherSubmitted(sv *paych0.SignedVoucher) error { +func (ci *ChannelInfo) markVoucherSubmitted(sv *paych.SignedVoucher) error { vi, err := ci.infoForVoucher(sv) if err != nil { return err @@ -148,7 +147,7 @@ func (ci *ChannelInfo) markVoucherSubmitted(sv *paych0.SignedVoucher) error { } // wasVoucherSubmitted returns true if the voucher has been submitted -func (ci *ChannelInfo) wasVoucherSubmitted(sv *paych0.SignedVoucher) (bool, error) { +func (ci *ChannelInfo) wasVoucherSubmitted(sv *paych.SignedVoucher) (bool, error) { vi, err := ci.infoForVoucher(sv) if err != nil { return false, err @@ -277,7 +276,7 @@ func (ps *Store) VouchersForPaych(ch address.Address) ([]*VoucherInfo, error) { return ci.Vouchers, nil } -func (ps *Store) MarkVoucherSubmitted(ci *ChannelInfo, sv *paych0.SignedVoucher) error { +func (ps *Store) MarkVoucherSubmitted(ci *ChannelInfo, sv *paych.SignedVoucher) error { err := ci.markVoucherSubmitted(sv) if err != nil { return err diff --git a/paychmgr/util.go b/paychmgr/util.go index 2a8181c15..8e5dd4fab 100644 --- a/paychmgr/util.go +++ b/paychmgr/util.go @@ -5,21 +5,21 @@ import ( "github.com/filecoin-project/go-address" - paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" ) type BestSpendableAPI interface { - PaychVoucherList(context.Context, address.Address) ([]*paych0.SignedVoucher, error) - PaychVoucherCheckSpendable(context.Context, address.Address, *paych0.SignedVoucher, []byte, []byte) (bool, error) + PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error) + PaychVoucherCheckSpendable(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) } -func BestSpendableByLane(ctx context.Context, api BestSpendableAPI, ch address.Address) (map[uint64]*paych0.SignedVoucher, error) { +func BestSpendableByLane(ctx context.Context, api BestSpendableAPI, ch address.Address) (map[uint64]*paych.SignedVoucher, error) { vouchers, err := api.PaychVoucherList(ctx, ch) if err != nil { return nil, err } - bestByLane := make(map[uint64]*paych0.SignedVoucher) + bestByLane := make(map[uint64]*paych.SignedVoucher) for _, voucher := range vouchers { spendable, err := api.PaychVoucherCheckSpendable(ctx, ch, voucher, nil, nil) if err != nil { diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 65dbd6e59..6aa3d5188 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -327,17 +327,22 @@ func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64, } for partIdx, partition := range partitions { - good, err := s.checkSectors(ctx, partition.ActiveSectors) + nonFaulty, err := bitfield.SubtractBitField(partition.LiveSectors, partition.FaultySectors) + if err != nil { + return nil, nil, xerrors.Errorf("determining non faulty sectors: %w", err) + } + + good, err := s.checkSectors(ctx, nonFaulty) if err != nil { return nil, nil, xerrors.Errorf("checking sectors: %w", err) } - faulty, err := bitfield.SubtractBitField(partition.ActiveSectors, good) + newFaulty, err := bitfield.SubtractBitField(nonFaulty, good) if err != nil { return nil, nil, xerrors.Errorf("calculating faulty sector set: %w", err) } - c, err := faulty.Count() + c, err := newFaulty.Count() if err != nil { return nil, nil, xerrors.Errorf("counting faulty sectors: %w", err) } @@ -351,7 +356,7 @@ func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64, params.Faults = append(params.Faults, miner.FaultDeclaration{ Deadline: dlIdx, Partition: uint64(partIdx), - Sectors: faulty, + Sectors: newFaulty, }) } @@ -509,7 +514,11 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty var sinfos []proof.SectorInfo for partIdx, partition := range batch { // TODO: Can do this in parallel - toProve, err := bitfield.MergeBitFields(partition.ActiveSectors, partition.RecoveringSectors) + toProve, err := bitfield.SubtractBitField(partition.LiveSectors, partition.FaultySectors) + if err != nil { + return nil, xerrors.Errorf("removing faults from set of sectors to prove: %w", err) + } + toProve, err = bitfield.MergeBitFields(toProve, partition.RecoveringSectors) if err != nil { return nil, xerrors.Errorf("adding recoveries to set of sectors to prove: %w", err) }