diff --git a/.circleci/config.yml b/.circleci/config.yml index 98474ab7f..40e2bb2b1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -130,6 +130,9 @@ jobs: winpost-test: type: string default: "0" + deadline-test: + type: string + default: "0" test-suite-name: type: string default: unit @@ -163,6 +166,7 @@ jobs: name: go test environment: LOTUS_TEST_WINDOW_POST: << parameters.winpost-test >> + LOTUS_TEST_DEADLINE_TOGGLING: << parameters.deadline-test >> SKIP_CONFORMANCE: "1" command: | mkdir -p /tmp/test-reports/<< parameters.test-suite-name >> @@ -204,6 +208,8 @@ jobs: <<: *test test-window-post-dispute: <<: *test + test-deadline-toggling: + <<: *test test-terminate: <<: *test test-conformance: @@ -730,6 +736,11 @@ workflows: go-test-flags: "-run=TestTerminate" winpost-test: "1" test-suite-name: terminate + - test-deadline-toggling: + codecov-upload: true + go-test-flags: "-run=TestDeadlineToggling" + deadline-test: "1" + test-suite-name: deadline-toggling - test-short: go-test-flags: "--timeout 10m --short" test-suite-name: short diff --git a/CHANGELOG.md b/CHANGELOG.md index 49ce31bcd..40d088195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,14 @@ This is an optional Lotus release that introduces various improvements to the se - fix 4857: show help for set-addrs (https://github.com/filecoin-project/lotus/pull/5943) - fix health report (https://github.com/filecoin-project/lotus/pull/6011) +# 1.8.0 / 2021-04-05 + +This is a mandatory release of Lotus that upgrades the network to version 12, which introduces various performance improvements to the cron processing of the power actor. The network will upgrade at height 712320, which is 2021-04-29T06:00:00Z. + +## Changes + +- v4 specs-actors integration, nv12 migration (https://github.com/filecoin-project/lotus/pull/6116) + # 1.6.0 / 2021-04-05 This is a mandatory release of Lotus that upgrades the network to version 11, which implements [FIP-0014](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0014.md). The network will upgrade at height 665280, which is 2021-04-12T22:00:00Z. diff --git a/api/test/ccupgrade.go b/api/test/ccupgrade.go index 606b9f22b..8c2bdc9b4 100644 --- a/api/test/ccupgrade.go +++ b/api/test/ccupgrade.go @@ -17,7 +17,7 @@ import ( func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) { for _, height := range []abi.ChainEpoch{ - 2, // before + -1, // before 162, // while sealing 530, // after upgrade deal 5000, // after @@ -31,7 +31,7 @@ func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) { func testCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, upgradeHeight abi.ChainEpoch) { ctx := context.Background() - n, sn := b(t, []FullNodeOpts{FullNodeWithActorsV3At(upgradeHeight)}, OneMiner) + n, sn := b(t, []FullNodeOpts{FullNodeWithActorsV4At(upgradeHeight)}, OneMiner) client := n[0].FullNode.(*impl.FullNodeAPI) miner := sn[0] diff --git a/api/test/deadlines.go b/api/test/deadlines.go new file mode 100644 index 000000000..c896e7e00 --- /dev/null +++ b/api/test/deadlines.go @@ -0,0 +1,350 @@ +package test + +import ( + "bytes" + "context" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "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/big" + "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/go-state-types/network" + miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/extern/sector-storage/mock" + "github.com/filecoin-project/lotus/node/impl" +) + +// TestDeadlineToggling: +// * spins up a v3 network (miner A) +// * creates an inactive miner (miner B) +// * creates another miner, pledges a sector, waits for power (miner C) +// +// * goes through v4 upgrade +// * goes through PP +// * creates minerD, minerE +// * makes sure that miner B/D are inactive, A/C still are +// * pledges sectors on miner B/D +// * precommits a sector on minerE +// * disables post on miner C +// * goes through PP 0.5PP +// * asserts that minerE is active +// * goes through rest of PP (1.5) +// * asserts that miner C loses power +// * asserts that miner B/D is active and has power +// * asserts that minerE is inactive +// * disables post on miner B +// * terminates sectors on miner D +// * goes through another PP +// * asserts that miner B loses power +// * asserts that miner D loses power, is inactive +func TestDeadlineToggling(t *testing.T, b APIBuilder, blocktime time.Duration) { + var upgradeH abi.ChainEpoch = 4000 + var provingPeriod abi.ChainEpoch = 2880 + + const sectorsC, sectorsD, sectersB = 10, 9, 8 + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + n, sn := b(t, []FullNodeOpts{FullNodeWithActorsV4At(upgradeH)}, OneMiner) + + client := n[0].FullNode.(*impl.FullNodeAPI) + minerA := sn[0] + + { + addrinfo, err := client.NetAddrsListen(ctx) + if err != nil { + t.Fatal(err) + } + + if err := minerA.NetConnect(ctx, addrinfo); err != nil { + t.Fatal(err) + } + } + + defaultFrom, err := client.WalletDefaultAddress(ctx) + require.NoError(t, err) + + maddrA, err := minerA.ActorAddress(ctx) + require.NoError(t, err) + + build.Clock.Sleep(time.Second) + + done := make(chan struct{}) + go func() { + defer close(done) + for ctx.Err() == nil { + build.Clock.Sleep(blocktime) + if err := minerA.MineOne(ctx, MineNext); err != nil { + if ctx.Err() != nil { + // context was canceled, ignore the error. + return + } + t.Error(err) + } + } + }() + defer func() { + cancel() + <-done + }() + + minerB := n[0].Stb(ctx, t, TestSpt, defaultFrom) + minerC := n[0].Stb(ctx, t, TestSpt, defaultFrom) + + maddrB, err := minerB.ActorAddress(ctx) + require.NoError(t, err) + maddrC, err := minerC.ActorAddress(ctx) + require.NoError(t, err) + + ssz, err := minerC.ActorSectorSize(ctx, maddrC) + require.NoError(t, err) + + // pledge sectors on C, go through a PP, check for power + { + pledgeSectors(t, ctx, minerC, sectorsC, 0, nil) + + di, err := client.StateMinerProvingDeadline(ctx, maddrC, types.EmptyTSK) + require.NoError(t, err) + + fmt.Printf("Running one proving period (miner C)\n") + fmt.Printf("End for head.Height > %d\n", di.PeriodStart+di.WPoStProvingPeriod*2) + + for { + head, err := client.ChainHead(ctx) + require.NoError(t, err) + + if head.Height() > di.PeriodStart+provingPeriod*2 { + fmt.Printf("Now head.Height = %d\n", head.Height()) + break + } + build.Clock.Sleep(blocktime) + } + + expectedPower := types.NewInt(uint64(ssz) * sectorsC) + + p, err := client.StateMinerPower(ctx, maddrC, types.EmptyTSK) + require.NoError(t, err) + + // make sure it has gained power. + require.Equal(t, p.MinerPower.RawBytePower, expectedPower) + } + + // go through upgrade + PP + for { + head, err := client.ChainHead(ctx) + require.NoError(t, err) + + if head.Height() > upgradeH+provingPeriod { + fmt.Printf("Now head.Height = %d\n", head.Height()) + break + } + build.Clock.Sleep(blocktime) + } + + checkMiner := func(ma address.Address, power abi.StoragePower, active bool, tsk types.TipSetKey) { + p, err := client.StateMinerPower(ctx, ma, tsk) + require.NoError(t, err) + + // make sure it has the expected power. + require.Equal(t, p.MinerPower.RawBytePower, power) + + mact, err := client.StateGetActor(ctx, ma, tsk) + require.NoError(t, err) + + mst, err := miner.Load(adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(client))), mact) + require.NoError(t, err) + + act, err := mst.DeadlineCronActive() + require.NoError(t, err) + require.Equal(t, active, act) + } + + // check that just after the upgrade minerB was still active + { + uts, err := client.ChainGetTipSetByHeight(ctx, upgradeH+2, types.EmptyTSK) + require.NoError(t, err) + checkMiner(maddrB, types.NewInt(0), true, uts.Key()) + } + + nv, err := client.StateNetworkVersion(ctx, types.EmptyTSK) + require.NoError(t, err) + require.GreaterOrEqual(t, nv, network.Version12) + + minerD := n[0].Stb(ctx, t, TestSpt, defaultFrom) + minerE := n[0].Stb(ctx, t, TestSpt, defaultFrom) + + maddrD, err := minerD.ActorAddress(ctx) + require.NoError(t, err) + maddrE, err := minerE.ActorAddress(ctx) + require.NoError(t, err) + + // first round of miner checks + checkMiner(maddrA, types.NewInt(uint64(ssz)*GenesisPreseals), true, types.EmptyTSK) + checkMiner(maddrC, types.NewInt(uint64(ssz)*sectorsC), true, types.EmptyTSK) + + checkMiner(maddrB, types.NewInt(0), false, types.EmptyTSK) + checkMiner(maddrD, types.NewInt(0), false, types.EmptyTSK) + checkMiner(maddrE, types.NewInt(0), false, types.EmptyTSK) + + // pledge sectors on minerB/minerD, stop post on minerC + pledgeSectors(t, ctx, minerB, sectersB, 0, nil) + checkMiner(maddrB, types.NewInt(0), true, types.EmptyTSK) + + pledgeSectors(t, ctx, minerD, sectorsD, 0, nil) + checkMiner(maddrD, types.NewInt(0), true, types.EmptyTSK) + + minerC.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).Fail() + + // precommit a sector on minerE + { + head, err := client.ChainHead(ctx) + require.NoError(t, err) + + cr, err := cid.Parse("bagboea4b5abcatlxechwbp7kjpjguna6r6q7ejrhe6mdp3lf34pmswn27pkkiekz") + require.NoError(t, err) + + params := &miner.SectorPreCommitInfo{ + Expiration: 2880 * 300, + SectorNumber: 22, + SealProof: TestSpt, + + SealedCID: cr, + SealRandEpoch: head.Height() - 200, + } + + enc := new(bytes.Buffer) + require.NoError(t, params.MarshalCBOR(enc)) + + m, err := client.MpoolPushMessage(ctx, &types.Message{ + To: maddrE, + From: defaultFrom, + Value: types.FromFil(1), + Method: miner.Methods.PreCommitSector, + Params: enc.Bytes(), + }, nil) + require.NoError(t, err) + + r, err := client.StateWaitMsg(ctx, m.Cid(), 2) + require.NoError(t, err) + require.Equal(t, exitcode.Ok, r.Receipt.ExitCode) + } + + // go through 0.5 PP + for { + head, err := client.ChainHead(ctx) + require.NoError(t, err) + + if head.Height() > upgradeH+provingPeriod+(provingPeriod/2) { + fmt.Printf("Now head.Height = %d\n", head.Height()) + break + } + build.Clock.Sleep(blocktime) + } + + checkMiner(maddrE, types.NewInt(0), true, types.EmptyTSK) + + // go through rest of the PP + for { + head, err := client.ChainHead(ctx) + require.NoError(t, err) + + if head.Height() > upgradeH+(provingPeriod*3) { + fmt.Printf("Now head.Height = %d\n", head.Height()) + break + } + build.Clock.Sleep(blocktime) + } + + // second round of miner checks + checkMiner(maddrA, types.NewInt(uint64(ssz)*GenesisPreseals), true, types.EmptyTSK) + checkMiner(maddrC, types.NewInt(0), true, types.EmptyTSK) + checkMiner(maddrB, types.NewInt(uint64(ssz)*sectersB), true, types.EmptyTSK) + checkMiner(maddrD, types.NewInt(uint64(ssz)*sectorsD), true, types.EmptyTSK) + checkMiner(maddrE, types.NewInt(0), false, types.EmptyTSK) + + // disable post on minerB + minerB.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).Fail() + + // terminate sectors on minerD + { + var terminationDeclarationParams []miner2.TerminationDeclaration + secs, err := minerD.SectorsList(ctx) + require.NoError(t, err) + require.Len(t, secs, sectorsD) + + for _, sectorNum := range secs { + sectorbit := bitfield.New() + sectorbit.Set(uint64(sectorNum)) + + loca, err := client.StateSectorPartition(ctx, maddrD, sectorNum, types.EmptyTSK) + require.NoError(t, err) + + para := miner2.TerminationDeclaration{ + Deadline: loca.Deadline, + Partition: loca.Partition, + Sectors: sectorbit, + } + + terminationDeclarationParams = append(terminationDeclarationParams, para) + } + + terminateSectorParams := &miner2.TerminateSectorsParams{ + Terminations: terminationDeclarationParams, + } + + sp, aerr := actors.SerializeParams(terminateSectorParams) + require.NoError(t, aerr) + + smsg, err := client.MpoolPushMessage(ctx, &types.Message{ + From: defaultFrom, + To: maddrD, + Method: miner.Methods.TerminateSectors, + + Value: big.Zero(), + Params: sp, + }, nil) + require.NoError(t, err) + + fmt.Println("sent termination message:", smsg.Cid()) + + r, err := client.StateWaitMsg(ctx, smsg.Cid(), 2) + require.NoError(t, err) + require.Equal(t, exitcode.Ok, r.Receipt.ExitCode) + + checkMiner(maddrD, types.NewInt(0), true, r.TipSet) + } + + // go through another PP + for { + head, err := client.ChainHead(ctx) + require.NoError(t, err) + + if head.Height() > upgradeH+(provingPeriod*5) { + fmt.Printf("Now head.Height = %d\n", head.Height()) + break + } + build.Clock.Sleep(blocktime) + } + + // third round of miner checks + checkMiner(maddrA, types.NewInt(uint64(ssz)*GenesisPreseals), true, types.EmptyTSK) + checkMiner(maddrC, types.NewInt(0), true, types.EmptyTSK) + checkMiner(maddrB, types.NewInt(0), true, types.EmptyTSK) + checkMiner(maddrD, types.NewInt(0), false, types.EmptyTSK) +} diff --git a/api/test/mining.go b/api/test/mining.go index 8f3689333..8e300a9c9 100644 --- a/api/test/mining.go +++ b/api/test/mining.go @@ -11,10 +11,13 @@ import ( logging "github.com/ipfs/go-log/v2" - "github.com/filecoin-project/go-state-types/abi" "github.com/stretchr/testify/require" + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/miner" "github.com/filecoin-project/lotus/node/impl" ) @@ -199,3 +202,39 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo fmt.Println("shutting down mining") <-done } + +func (ts *testSuite) testNonGenesisMiner(t *testing.T) { + ctx := context.Background() + n, sn := ts.makeNodes(t, []FullNodeOpts{ + FullNodeWithActorsV4At(-1), + }, []StorageMiner{ + {Full: 0, Preseal: PresealGenesis}, + }) + + full, ok := n[0].FullNode.(*impl.FullNodeAPI) + if !ok { + t.Skip("not testing with a full node") + return + } + genesisMiner := sn[0] + + bm := NewBlockMiner(ctx, t, genesisMiner, 4*time.Millisecond) + bm.MineBlocks() + t.Cleanup(bm.Stop) + + gaa, err := genesisMiner.ActorAddress(ctx) + require.NoError(t, err) + + gmi, err := full.StateMinerInfo(ctx, gaa, types.EmptyTSK) + require.NoError(t, err) + + testm := n[0].Stb(ctx, t, TestSpt, gmi.Owner) + + ta, err := testm.ActorAddress(ctx) + require.NoError(t, err) + + tid, err := address.IDFromAddress(ta) + require.NoError(t, err) + + require.Equal(t, uint64(1001), tid) +} diff --git a/api/test/test.go b/api/test/test.go index eed760bc2..613a4f1dc 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -8,20 +8,21 @@ import ( "testing" "time" - "github.com/filecoin-project/lotus/chain/stmgr" - "github.com/filecoin-project/lotus/chain/types" - logging "github.com/ipfs/go-log/v2" "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "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/filecoin-project/lotus/api" "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/miner" "github.com/filecoin-project/lotus/node" ) @@ -35,11 +36,15 @@ func init() { build.InsecurePoStValidation = true } +type StorageBuilder func(context.Context, *testing.T, abi.RegisteredSealProof, address.Address) TestStorageNode + type TestNode struct { api.FullNode // ListenAddr is the address on which an API server is listening, if an // API server is created for this Node ListenAddr multiaddr.Multiaddr + + Stb StorageBuilder } type TestStorageNode struct { @@ -56,6 +61,8 @@ var PresealGenesis = -1 const GenesisPreseals = 2 +const TestSpt = abi.RegisteredSealProof_StackedDrg2KiBV1_1 + // Options for setting up a mock storage miner type StorageMiner struct { Full int @@ -94,6 +101,7 @@ func TestApis(t *testing.T, b APIBuilder) { t.Run("testMining", ts.testMining) t.Run("testMiningReal", ts.testMiningReal) t.Run("testSearchMsg", ts.testSearchMsg) + t.Run("testNonGenesisMiner", ts.testNonGenesisMiner) } func DefaultFullOpts(nFull int) []FullNodeOpts { @@ -112,7 +120,11 @@ var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}} var OneFull = DefaultFullOpts(1) var TwoFull = DefaultFullOpts(2) -var FullNodeWithActorsV3At = func(upgradeHeight abi.ChainEpoch) FullNodeOpts { +var FullNodeWithActorsV4At = func(upgradeHeight abi.ChainEpoch) FullNodeOpts { + if upgradeHeight == -1 { + upgradeHeight = 3 + } + return FullNodeOpts{ Opts: func(nodes []TestNode) node.Option { return node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{ @@ -121,10 +133,13 @@ var FullNodeWithActorsV3At = func(upgradeHeight abi.ChainEpoch) FullNodeOpts { Height: 1, Migration: stmgr.UpgradeActorsV2, }, { - // Skip directly to tape height so precommits work. Network: network.Version10, - Height: upgradeHeight, + Height: 2, Migration: stmgr.UpgradeActorsV3, + }, { + Network: network.Version12, + Height: upgradeHeight, + Migration: stmgr.UpgradeActorsV4, }}) }, } @@ -156,6 +171,9 @@ var MineNext = miner.MineReq{ func (ts *testSuite) testVersion(t *testing.T) { api.RunningNodeType = api.NodeFull + t.Cleanup(func() { + api.RunningNodeType = api.NodeUnknown + }) ctx := context.Background() apis, _ := ts.makeNodes(t, OneFull, OneMiner) diff --git a/api/test/window_post.go b/api/test/window_post.go index ce42318b2..4992741f4 100644 --- a/api/test/window_post.go +++ b/api/test/window_post.go @@ -206,7 +206,7 @@ func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n, func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) { for _, height := range []abi.ChainEpoch{ - 2, // before + -1, // before 162, // while sealing 5000, // while proving } { @@ -223,7 +223,7 @@ func testWindowPostUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, sn := b(t, []FullNodeOpts{FullNodeWithActorsV3At(upgradeHeight)}, OneMiner) + n, sn := b(t, []FullNodeOpts{FullNodeWithActorsV4At(upgradeHeight)}, OneMiner) client := n[0].FullNode.(*impl.FullNodeAPI) miner := sn[0] @@ -442,7 +442,7 @@ func TestTerminate(t *testing.T, b APIBuilder, blocktime time.Duration) { nSectors := uint64(2) - n, sn := b(t, []FullNodeOpts{FullNodeWithActorsV3At(2)}, []StorageMiner{{Full: 0, Preseal: int(nSectors)}}) + n, sn := b(t, []FullNodeOpts{FullNodeWithActorsV4At(-1)}, []StorageMiner{{Full: 0, Preseal: int(nSectors)}}) client := n[0].FullNode.(*impl.FullNodeAPI) miner := sn[0] @@ -617,7 +617,7 @@ func TestWindowPostDispute(t *testing.T, b APIBuilder, blocktime time.Duration) /// // Then we're going to manually submit bad proofs. n, sn := b(t, []FullNodeOpts{ - FullNodeWithActorsV3At(2), + FullNodeWithActorsV4At(-1), }, []StorageMiner{ {Full: 0, Preseal: PresealGenesis}, {Full: 0}, @@ -900,7 +900,7 @@ func TestWindowPostDisputeFails(t *testing.T, b APIBuilder, blocktime time.Durat ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, sn := b(t, []FullNodeOpts{FullNodeWithActorsV3At(2)}, OneMiner) + n, sn := b(t, []FullNodeOpts{FullNodeWithActorsV4At(-1)}, OneMiner) client := n[0].FullNode.(*impl.FullNodeAPI) miner := sn[0] diff --git a/api/version.go b/api/version.go index 17605b518..f1b0b3b9a 100644 --- a/api/version.go +++ b/api/version.go @@ -54,7 +54,7 @@ func VersionForType(nodeType NodeType) (Version, error) { // semver versions of the rpc api exposed var ( - FullAPIVersion = newVer(1, 1, 0) + FullAPIVersion = newVer(1, 2, 0) MinerAPIVersion = newVer(1, 0, 1) WorkerAPIVersion = newVer(1, 0, 0) ) diff --git a/build/params_2k.go b/build/params_2k.go index 1a63af5fa..12d497c4b 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -37,6 +37,8 @@ var UpgradeActorsV3Height = abi.ChainEpoch(35) var UpgradeNorwegianHeight = abi.ChainEpoch(40) +var UpgradeActorsV4Height = abi.ChainEpoch(45) + var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, } @@ -75,6 +77,7 @@ func init() { UpgradeClausHeight = getUpgradeHeight("LOTUS_CLAUS_HEIGHT", UpgradeClausHeight) UpgradeActorsV3Height = getUpgradeHeight("LOTUS_ACTORSV3_HEIGHT", UpgradeActorsV3Height) UpgradeNorwegianHeight = getUpgradeHeight("LOTUS_NORWEGIAN_HEIGHT", UpgradeNorwegianHeight) + UpgradeActorsV4Height = getUpgradeHeight("LOTUS_ACTORSV4_HEIGHT", UpgradeActorsV4Height) BuildType |= Build2k } diff --git a/build/params_butterfly.go b/build/params_butterfly.go index 3e9dbbbb8..6daeca502 100644 --- a/build/params_butterfly.go +++ b/build/params_butterfly.go @@ -34,6 +34,7 @@ const UpgradeClausHeight = 180 const UpgradeOrangeHeight = 210 const UpgradeActorsV3Height = 240 const UpgradeNorwegianHeight = UpgradeActorsV3Height + (builtin2.EpochsInHour * 12) +const UpgradeActorsV4Height = 8922 func init() { policy.SetConsensusMinerMinPower(abi.NewStoragePower(2 << 30)) diff --git a/build/params_calibnet.go b/build/params_calibnet.go index 10d29e564..997bb395b 100644 --- a/build/params_calibnet.go +++ b/build/params_calibnet.go @@ -43,6 +43,8 @@ const UpgradeOrangeHeight = 300 const UpgradeActorsV3Height = 600 const UpgradeNorwegianHeight = 114000 +const UpgradeActorsV4Height = 193789 + func init() { policy.SetConsensusMinerMinPower(abi.NewStoragePower(32 << 30)) policy.SetSupportedProofTypes( diff --git a/build/params_mainnet.go b/build/params_mainnet.go index d14b97e0f..ea4ae7d75 100644 --- a/build/params_mainnet.go +++ b/build/params_mainnet.go @@ -59,6 +59,9 @@ var UpgradeActorsV3Height = abi.ChainEpoch(550321) // 2021-04-12T22:00:00Z const UpgradeNorwegianHeight = 665280 +// 2021-04-29T06:00:00Z +var UpgradeActorsV4Height = abi.ChainEpoch(712320) + func init() { policy.SetConsensusMinerMinPower(abi.NewStoragePower(10 << 40)) @@ -70,6 +73,10 @@ func init() { UpgradeActorsV3Height = math.MaxInt64 } + if os.Getenv("LOTUS_DISABLE_V4_ACTOR_MIGRATION") == "1" { + UpgradeActorsV4Height = math.MaxInt64 + } + Devnet = false BuildType = BuildMainnet diff --git a/build/params_nerpanet.go b/build/params_nerpanet.go index 385000992..fb6cfc47a 100644 --- a/build/params_nerpanet.go +++ b/build/params_nerpanet.go @@ -41,6 +41,7 @@ const UpgradeOrangeHeight = 300 const UpgradeActorsV3Height = 600 const UpgradeNorwegianHeight = 999999 +const UpgradeActorsV4Height = 99999999 func init() { // Minimum block production power is set to 4 TiB diff --git a/build/params_testground.go b/build/params_testground.go index fd4298281..7da3c2272 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -95,6 +95,7 @@ var ( UpgradeClausHeight abi.ChainEpoch = -10 UpgradeActorsV3Height abi.ChainEpoch = -11 UpgradeNorwegianHeight abi.ChainEpoch = -12 + UpgradeActorsV4Height abi.ChainEpoch = -13 DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, diff --git a/chain/actors/builtin/account/account.go b/chain/actors/builtin/account/account.go index 53a03e6f3..4d94b245a 100644 --- a/chain/actors/builtin/account/account.go +++ b/chain/actors/builtin/account/account.go @@ -14,6 +14,7 @@ import ( builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" ) func init() { @@ -26,9 +27,12 @@ func init() { builtin.RegisterActorState(builtin3.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load3(store, root) }) + builtin.RegisterActorState(builtin4.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load4(store, root) + }) } -var Methods = builtin3.MethodsAccount +var Methods = builtin4.MethodsAccount func Load(store adt.Store, act *types.Actor) (State, error) { switch act.Code { @@ -38,6 +42,8 @@ func Load(store adt.Store, act *types.Actor) (State, error) { return load2(store, act.Head) case builtin3.AccountActorCodeID: return load3(store, act.Head) + case builtin4.AccountActorCodeID: + return load4(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/account/v4.go b/chain/actors/builtin/account/v4.go new file mode 100644 index 000000000..1a24007d8 --- /dev/null +++ b/chain/actors/builtin/account/v4.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" + + account4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/account" +) + +var _ State = (*state4)(nil) + +func load4(store adt.Store, root cid.Cid) (State, error) { + out := state4{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state4 struct { + account4.State + store adt.Store +} + +func (s *state4) PubkeyAddress() (address.Address, error) { + return s.Address, nil +} diff --git a/chain/actors/builtin/builtin.go b/chain/actors/builtin/builtin.go index 045048d1f..4ff524797 100644 --- a/chain/actors/builtin/builtin.go +++ b/chain/actors/builtin/builtin.go @@ -8,6 +8,7 @@ import ( builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/cbor" @@ -18,6 +19,7 @@ import ( smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing" smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing" smoothing3 "github.com/filecoin-project/specs-actors/v3/actors/util/smoothing" + smoothing4 "github.com/filecoin-project/specs-actors/v4/actors/util/smoothing" miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof" @@ -41,8 +43,8 @@ const ( ) const ( - MethodSend = builtin3.MethodSend - MethodConstructor = builtin3.MethodConstructor + MethodSend = builtin4.MethodSend + MethodConstructor = builtin4.MethodConstructor ) // These are all just type aliases across actor versions 0, 2, & 3. In the future, that might change @@ -68,6 +70,10 @@ func FromV3FilterEstimate(v3 smoothing3.FilterEstimate) FilterEstimate { return (FilterEstimate)(v3) } +func FromV4FilterEstimate(v4 smoothing4.FilterEstimate) FilterEstimate { + return (FilterEstimate)(v4) +} + type ActorStateLoader func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) var ActorStateLoaders = make(map[cid.Cid]ActorStateLoader) @@ -92,6 +98,8 @@ func ActorNameByCode(c cid.Cid) string { return builtin2.ActorNameByCode(c) case builtin3.IsBuiltinActor(c): return builtin3.ActorNameByCode(c) + case builtin4.IsBuiltinActor(c): + return builtin4.ActorNameByCode(c) default: return "" } @@ -100,32 +108,36 @@ func ActorNameByCode(c cid.Cid) string { func IsBuiltinActor(c cid.Cid) bool { return builtin0.IsBuiltinActor(c) || builtin2.IsBuiltinActor(c) || - builtin3.IsBuiltinActor(c) + builtin3.IsBuiltinActor(c) || + builtin4.IsBuiltinActor(c) } func IsAccountActor(c cid.Cid) bool { return c == builtin0.AccountActorCodeID || c == builtin2.AccountActorCodeID || - c == builtin3.AccountActorCodeID + c == builtin3.AccountActorCodeID || + c == builtin4.AccountActorCodeID } func IsStorageMinerActor(c cid.Cid) bool { return c == builtin0.StorageMinerActorCodeID || c == builtin2.StorageMinerActorCodeID || - c == builtin3.StorageMinerActorCodeID + c == builtin3.StorageMinerActorCodeID || + c == builtin4.StorageMinerActorCodeID } func IsMultisigActor(c cid.Cid) bool { return c == builtin0.MultisigActorCodeID || c == builtin2.MultisigActorCodeID || - c == builtin3.MultisigActorCodeID - + c == builtin3.MultisigActorCodeID || + c == builtin4.MultisigActorCodeID } func IsPaymentChannelActor(c cid.Cid) bool { return c == builtin0.PaymentChannelActorCodeID || c == builtin2.PaymentChannelActorCodeID || - c == builtin3.PaymentChannelActorCodeID + c == builtin3.PaymentChannelActorCodeID || + c == builtin4.PaymentChannelActorCodeID } func makeAddress(addr string) address.Address { diff --git a/chain/actors/builtin/cron/cron.go b/chain/actors/builtin/cron/cron.go index 284aad82e..52a9fab07 100644 --- a/chain/actors/builtin/cron/cron.go +++ b/chain/actors/builtin/cron/cron.go @@ -1,10 +1,10 @@ package cron import ( - builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" ) var ( - Address = builtin3.CronActorAddr - Methods = builtin3.MethodsCron + Address = builtin4.CronActorAddr + Methods = builtin4.MethodsCron ) diff --git a/chain/actors/builtin/init/init.go b/chain/actors/builtin/init/init.go index f9e912768..697148641 100644 --- a/chain/actors/builtin/init/init.go +++ b/chain/actors/builtin/init/init.go @@ -16,6 +16,7 @@ import ( builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" ) func init() { @@ -28,11 +29,14 @@ func init() { builtin.RegisterActorState(builtin3.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load3(store, root) }) + builtin.RegisterActorState(builtin4.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load4(store, root) + }) } var ( - Address = builtin3.InitActorAddr - Methods = builtin3.MethodsInit + Address = builtin4.InitActorAddr + Methods = builtin4.MethodsInit ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -43,6 +47,8 @@ func Load(store adt.Store, act *types.Actor) (State, error) { return load2(store, act.Head) case builtin3.InitActorCodeID: return load3(store, act.Head) + case builtin4.InitActorCodeID: + return load4(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/init/v4.go b/chain/actors/builtin/init/v4.go new file mode 100644 index 000000000..a2be603a3 --- /dev/null +++ b/chain/actors/builtin/init/v4.go @@ -0,0 +1,86 @@ +package init + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" + "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" + + init4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/init" + adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" +) + +var _ State = (*state4)(nil) + +func load4(store adt.Store, root cid.Cid) (State, error) { + out := state4{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state4 struct { + init4.State + store adt.Store +} + +func (s *state4) ResolveAddress(address address.Address) (address.Address, bool, error) { + return s.State.ResolveAddress(s.store, address) +} + +func (s *state4) MapAddressToNewID(address address.Address) (address.Address, error) { + return s.State.MapAddressToNewID(s.store, address) +} + +func (s *state4) ForEachActor(cb func(id abi.ActorID, address address.Address) error) error { + addrs, err := adt4.AsMap(s.store, s.State.AddressMap, builtin4.DefaultHamtBitwidth) + 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 *state4) NetworkName() (dtypes.NetworkName, error) { + return dtypes.NetworkName(s.State.NetworkName), nil +} + +func (s *state4) SetNetworkName(name string) error { + s.State.NetworkName = name + return nil +} + +func (s *state4) Remove(addrs ...address.Address) (err error) { + m, err := adt4.AsMap(s.store, s.State.AddressMap, builtin4.DefaultHamtBitwidth) + 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 +} + +func (s *state4) addressMap() (adt.Map, error) { + return adt4.AsMap(s.store, s.AddressMap, builtin4.DefaultHamtBitwidth) +} diff --git a/chain/actors/builtin/market/market.go b/chain/actors/builtin/market/market.go index 0e4d9e01b..738151503 100644 --- a/chain/actors/builtin/market/market.go +++ b/chain/actors/builtin/market/market.go @@ -13,6 +13,7 @@ import ( market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -29,11 +30,14 @@ func init() { builtin.RegisterActorState(builtin3.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load3(store, root) }) + builtin.RegisterActorState(builtin4.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load4(store, root) + }) } var ( - Address = builtin3.StorageMarketActorAddr - Methods = builtin3.MethodsMarket + Address = builtin4.StorageMarketActorAddr + Methods = builtin4.MethodsMarket ) func Load(store adt.Store, act *types.Actor) (st State, err error) { @@ -44,6 +48,8 @@ func Load(store adt.Store, act *types.Actor) (st State, err error) { return load2(store, act.Head) case builtin3.StorageMarketActorCodeID: return load3(store, act.Head) + case builtin4.StorageMarketActorCodeID: + return load4(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/market/v4.go b/chain/actors/builtin/market/v4.go new file mode 100644 index 000000000..dede98d1a --- /dev/null +++ b/chain/actors/builtin/market/v4.go @@ -0,0 +1,209 @@ +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" + + market4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/market" + adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" +) + +var _ State = (*state4)(nil) + +func load4(store adt.Store, root cid.Cid) (State, error) { + out := state4{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state4 struct { + market4.State + store adt.Store +} + +func (s *state4) TotalLocked() (abi.TokenAmount, error) { + fml := types.BigAdd(s.TotalClientLockedCollateral, s.TotalProviderLockedCollateral) + fml = types.BigAdd(fml, s.TotalClientStorageFee) + return fml, nil +} + +func (s *state4) BalancesChanged(otherState State) (bool, error) { + otherState2, ok := otherState.(*state4) + 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 *state4) StatesChanged(otherState State) (bool, error) { + otherState2, ok := otherState.(*state4) + 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 *state4) States() (DealStates, error) { + stateArray, err := adt4.AsArray(s.store, s.State.States, market4.StatesAmtBitwidth) + if err != nil { + return nil, err + } + return &dealStates4{stateArray}, nil +} + +func (s *state4) ProposalsChanged(otherState State) (bool, error) { + otherState2, ok := otherState.(*state4) + 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 *state4) Proposals() (DealProposals, error) { + proposalArray, err := adt4.AsArray(s.store, s.State.Proposals, market4.ProposalsAmtBitwidth) + if err != nil { + return nil, err + } + return &dealProposals4{proposalArray}, nil +} + +func (s *state4) EscrowTable() (BalanceTable, error) { + bt, err := adt4.AsBalanceTable(s.store, s.State.EscrowTable) + if err != nil { + return nil, err + } + return &balanceTable4{bt}, nil +} + +func (s *state4) LockedTable() (BalanceTable, error) { + bt, err := adt4.AsBalanceTable(s.store, s.State.LockedTable) + if err != nil { + return nil, err + } + return &balanceTable4{bt}, nil +} + +func (s *state4) VerifyDealsForActivation( + minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch, +) (weight, verifiedWeight abi.DealWeight, err error) { + w, vw, _, err := market4.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch) + return w, vw, err +} + +func (s *state4) NextID() (abi.DealID, error) { + return s.State.NextID, nil +} + +type balanceTable4 struct { + *adt4.BalanceTable +} + +func (bt *balanceTable4) ForEach(cb func(address.Address, abi.TokenAmount) error) error { + asMap := (*adt4.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 dealStates4 struct { + adt.Array +} + +func (s *dealStates4) Get(dealID abi.DealID) (*DealState, bool, error) { + var deal2 market4.DealState + found, err := s.Array.Get(uint64(dealID), &deal2) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + deal := fromV4DealState(deal2) + return &deal, true, nil +} + +func (s *dealStates4) ForEach(cb func(dealID abi.DealID, ds DealState) error) error { + var ds1 market4.DealState + return s.Array.ForEach(&ds1, func(idx int64) error { + return cb(abi.DealID(idx), fromV4DealState(ds1)) + }) +} + +func (s *dealStates4) decode(val *cbg.Deferred) (*DealState, error) { + var ds1 market4.DealState + if err := ds1.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + ds := fromV4DealState(ds1) + return &ds, nil +} + +func (s *dealStates4) array() adt.Array { + return s.Array +} + +func fromV4DealState(v4 market4.DealState) DealState { + return (DealState)(v4) +} + +type dealProposals4 struct { + adt.Array +} + +func (s *dealProposals4) Get(dealID abi.DealID) (*DealProposal, bool, error) { + var proposal2 market4.DealProposal + found, err := s.Array.Get(uint64(dealID), &proposal2) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + proposal := fromV4DealProposal(proposal2) + return &proposal, true, nil +} + +func (s *dealProposals4) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error { + var dp1 market4.DealProposal + return s.Array.ForEach(&dp1, func(idx int64) error { + return cb(abi.DealID(idx), fromV4DealProposal(dp1)) + }) +} + +func (s *dealProposals4) decode(val *cbg.Deferred) (*DealProposal, error) { + var dp1 market4.DealProposal + if err := dp1.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + dp := fromV4DealProposal(dp1) + return &dp, nil +} + +func (s *dealProposals4) array() adt.Array { + return s.Array +} + +func fromV4DealProposal(v4 market4.DealProposal) DealProposal { + return (DealProposal)(v4) +} diff --git a/chain/actors/builtin/miner/miner.go b/chain/actors/builtin/miner/miner.go index 5bae8dea6..8fffcc8d6 100644 --- a/chain/actors/builtin/miner/miner.go +++ b/chain/actors/builtin/miner/miner.go @@ -24,6 +24,7 @@ import ( miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" miner3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/miner" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" ) func init() { @@ -36,11 +37,14 @@ func init() { builtin.RegisterActorState(builtin3.StorageMinerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load3(store, root) }) + builtin.RegisterActorState(builtin4.StorageMinerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load4(store, root) + }) } -var Methods = builtin3.MethodsMiner +var Methods = builtin4.MethodsMiner -// Unchanged between v0, v2, and v3 actors +// Unchanged between v0, v2, v3, and v4 actors var WPoStProvingPeriod = miner0.WPoStProvingPeriod var WPoStPeriodDeadlines = miner0.WPoStPeriodDeadlines var WPoStChallengeWindow = miner0.WPoStChallengeWindow @@ -62,6 +66,8 @@ func Load(store adt.Store, act *types.Actor) (st State, err error) { return load2(store, act.Head) case builtin3.StorageMinerActorCodeID: return load3(store, act.Head) + case builtin4.StorageMinerActorCodeID: + return load4(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -94,6 +100,7 @@ type State interface { MinerInfoChanged(State) (bool, error) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) + DeadlineCronActive() (bool, error) // Diff helpers. Used by Diff* functions internally. sectors() (adt.Array, error) diff --git a/chain/actors/builtin/miner/v0.go b/chain/actors/builtin/miner/v0.go index ebe5cf085..4f02e313f 100644 --- a/chain/actors/builtin/miner/v0.go +++ b/chain/actors/builtin/miner/v0.go @@ -330,6 +330,10 @@ func (s *state0) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) { return s.State.DeadlineInfo(epoch), nil } +func (s *state0) DeadlineCronActive() (bool, error) { + return true, nil // always active in this version +} + func (s *state0) sectors() (adt.Array, error) { return adt0.AsArray(s.store, s.Sectors) } diff --git a/chain/actors/builtin/miner/v2.go b/chain/actors/builtin/miner/v2.go index 79f984213..1720b619f 100644 --- a/chain/actors/builtin/miner/v2.go +++ b/chain/actors/builtin/miner/v2.go @@ -329,6 +329,10 @@ func (s *state2) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) { return s.State.DeadlineInfo(epoch), nil } +func (s *state2) DeadlineCronActive() (bool, error) { + return true, nil // always active in this version +} + func (s *state2) sectors() (adt.Array, error) { return adt2.AsArray(s.store, s.Sectors) } diff --git a/chain/actors/builtin/miner/v3.go b/chain/actors/builtin/miner/v3.go index 3379e720e..5e058ed1f 100644 --- a/chain/actors/builtin/miner/v3.go +++ b/chain/actors/builtin/miner/v3.go @@ -325,6 +325,10 @@ func (s *state3) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) { return s.State.DeadlineInfo(epoch), nil } +func (s *state3) DeadlineCronActive() (bool, error) { + return true, nil // always active in this version +} + func (s *state3) sectors() (adt.Array, error) { return adt3.AsArray(s.store, s.Sectors, miner3.SectorsAmtBitwidth) } diff --git a/chain/actors/builtin/miner/v4.go b/chain/actors/builtin/miner/v4.go new file mode 100644 index 000000000..b354dbc33 --- /dev/null +++ b/chain/actors/builtin/miner/v4.go @@ -0,0 +1,438 @@ +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" + + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" + miner4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" + adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" +) + +var _ State = (*state4)(nil) + +func load4(store adt.Store, root cid.Cid) (State, error) { + out := state4{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state4 struct { + miner4.State + store adt.Store +} + +type deadline4 struct { + miner4.Deadline + store adt.Store +} + +type partition4 struct { + miner4.Partition + store adt.Store +} + +func (s *state4) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) { + defer func() { + if r := recover(); r != nil { + err = xerrors.Errorf("failed to get available balance: %w", r) + available = abi.NewTokenAmount(0) + } + }() + // this panics if the miner doesnt have enough funds to cover their locked pledge + available, err = s.GetAvailableBalance(bal) + return available, err +} + +func (s *state4) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.CheckVestedFunds(s.store, epoch) +} + +func (s *state4) LockedFunds() (LockedFunds, error) { + return LockedFunds{ + VestingFunds: s.State.LockedFunds, + InitialPledgeRequirement: s.State.InitialPledge, + PreCommitDeposits: s.State.PreCommitDeposits, + }, nil +} + +func (s *state4) FeeDebt() (abi.TokenAmount, error) { + return s.State.FeeDebt, nil +} + +func (s *state4) InitialPledge() (abi.TokenAmount, error) { + return s.State.InitialPledge, nil +} + +func (s *state4) PreCommitDeposits() (abi.TokenAmount, error) { + return s.State.PreCommitDeposits, nil +} + +func (s *state4) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { + info, ok, err := s.State.GetSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV4SectorOnChainInfo(*info) + return &ret, nil +} + +func (s *state4) 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 *state4) 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 *miner4.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 *state4) 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 *miner4.Deadline) error { + partitions, err := dl.PartitionsArray(s.store) + if err != nil { + return err + } + quant := s.State.QuantSpecForDeadline(dlIdx) + var part miner4.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 := miner4.LoadExpirationQueue(s.store, part.ExpirationsEpochs, quant, miner4.PartitionExpirationAmtBitwidth) + if err != nil { + return err + } + var exp miner4.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 *state4) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { + info, ok, err := s.State.GetPrecommittedSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV4SectorPreCommitOnChainInfo(*info) + + return &ret, nil +} + +func (s *state4) LoadSectors(snos *bitfield.BitField) ([]*SectorOnChainInfo, error) { + sectors, err := miner4.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 miner4.SectorOnChainInfo + if err := sectors.ForEach(&info2, func(_ int64) error { + info := fromV4SectorOnChainInfo(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 := fromV4SectorOnChainInfo(*info2) + infos[i] = &info + } + return infos, nil +} + +func (s *state4) 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 *state4) 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 &deadline4{*dl, s.store}, nil +} + +func (s *state4) 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 *miner4.Deadline) error { + return cb(i, &deadline4{*dl, s.store}) + }) +} + +func (s *state4) NumDeadlines() (uint64, error) { + return miner4.WPoStPeriodDeadlines, nil +} + +func (s *state4) DeadlinesChanged(other State) (bool, error) { + other2, ok := other.(*state4) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return !s.State.Deadlines.Equals(other2.Deadlines), nil +} + +func (s *state4) MinerInfoChanged(other State) (bool, error) { + other0, ok := other.(*state4) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.Info.Equals(other0.State.Info), nil +} + +func (s *state4) 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, + WindowPoStProofType: info.WindowPoStProofType, + SectorSize: info.SectorSize, + WindowPoStPartitionSectors: info.WindowPoStPartitionSectors, + ConsensusFaultElapsed: info.ConsensusFaultElapsed, + } + + if info.PendingWorkerKey != nil { + mi.NewWorker = info.PendingWorkerKey.NewWorker + mi.WorkerChangeEpoch = info.PendingWorkerKey.EffectiveAt + } + + return mi, nil +} + +func (s *state4) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) { + return s.State.RecordedDeadlineInfo(epoch), nil +} + +func (s *state4) DeadlineCronActive() (bool, error) { + return s.State.DeadlineCronActive, nil +} + +func (s *state4) sectors() (adt.Array, error) { + return adt4.AsArray(s.store, s.Sectors, miner4.SectorsAmtBitwidth) +} + +func (s *state4) decodeSectorOnChainInfo(val *cbg.Deferred) (SectorOnChainInfo, error) { + var si miner4.SectorOnChainInfo + err := si.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorOnChainInfo{}, err + } + + return fromV4SectorOnChainInfo(si), nil +} + +func (s *state4) precommits() (adt.Map, error) { + return adt4.AsMap(s.store, s.PreCommittedSectors, builtin4.DefaultHamtBitwidth) +} + +func (s *state4) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { + var sp miner4.SectorPreCommitOnChainInfo + err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorPreCommitOnChainInfo{}, err + } + + return fromV4SectorPreCommitOnChainInfo(sp), nil +} + +func (d *deadline4) LoadPartition(idx uint64) (Partition, error) { + p, err := d.Deadline.LoadPartition(d.store, idx) + if err != nil { + return nil, err + } + return &partition4{*p, d.store}, nil +} + +func (d *deadline4) ForEachPartition(cb func(uint64, Partition) error) error { + ps, err := d.Deadline.PartitionsArray(d.store) + if err != nil { + return err + } + var part miner4.Partition + return ps.ForEach(&part, func(i int64) error { + return cb(uint64(i), &partition4{part, d.store}) + }) +} + +func (d *deadline4) PartitionsChanged(other Deadline) (bool, error) { + other2, ok := other.(*deadline4) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return !d.Deadline.Partitions.Equals(other2.Deadline.Partitions), nil +} + +func (d *deadline4) PartitionsPoSted() (bitfield.BitField, error) { + return d.Deadline.PartitionsPoSted, nil +} + +func (d *deadline4) DisputableProofCount() (uint64, error) { + ops, err := d.OptimisticProofsSnapshotArray(d.store) + if err != nil { + return 0, err + } + + return ops.Length(), nil +} + +func (p *partition4) AllSectors() (bitfield.BitField, error) { + return p.Partition.Sectors, nil +} + +func (p *partition4) FaultySectors() (bitfield.BitField, error) { + return p.Partition.Faults, nil +} + +func (p *partition4) RecoveringSectors() (bitfield.BitField, error) { + return p.Partition.Recoveries, nil +} + +func fromV4SectorOnChainInfo(v4 miner4.SectorOnChainInfo) SectorOnChainInfo { + return SectorOnChainInfo{ + SectorNumber: v4.SectorNumber, + SealProof: v4.SealProof, + SealedCID: v4.SealedCID, + DealIDs: v4.DealIDs, + Activation: v4.Activation, + Expiration: v4.Expiration, + DealWeight: v4.DealWeight, + VerifiedDealWeight: v4.VerifiedDealWeight, + InitialPledge: v4.InitialPledge, + ExpectedDayReward: v4.ExpectedDayReward, + ExpectedStoragePledge: v4.ExpectedStoragePledge, + } +} + +func fromV4SectorPreCommitOnChainInfo(v4 miner4.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + return SectorPreCommitOnChainInfo{ + Info: (SectorPreCommitInfo)(v4.Info), + PreCommitDeposit: v4.PreCommitDeposit, + PreCommitEpoch: v4.PreCommitEpoch, + DealWeight: v4.DealWeight, + VerifiedDealWeight: v4.VerifiedDealWeight, + } +} diff --git a/chain/actors/builtin/multisig/message.go b/chain/actors/builtin/multisig/message.go index 223bc4bc5..096049002 100644 --- a/chain/actors/builtin/multisig/message.go +++ b/chain/actors/builtin/multisig/message.go @@ -9,14 +9,14 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" - multisig3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/multisig" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" + multisig4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/multisig" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" ) -var Methods = builtin3.MethodsMultisig +var Methods = builtin4.MethodsMultisig func Message(version actors.Version, from address.Address) MessageBuilder { switch version { @@ -26,6 +26,8 @@ func Message(version actors.Version, from address.Address) MessageBuilder { return message2{message0{from}} case actors.Version3: return message3{message0{from}} + case actors.Version4: + return message4{message0{from}} default: panic(fmt.Sprintf("unsupported actors version: %d", version)) } @@ -49,12 +51,12 @@ type MessageBuilder interface { } // this type is the same between v0 and v2 -type ProposalHashData = multisig3.ProposalHashData -type ProposeReturn = multisig3.ProposeReturn -type ProposeParams = multisig3.ProposeParams +type ProposalHashData = multisig4.ProposalHashData +type ProposeReturn = multisig4.ProposeReturn +type ProposeParams = multisig4.ProposeParams func txnParams(id uint64, data *ProposalHashData) ([]byte, error) { - params := multisig3.TxnIDParams{ID: multisig3.TxnID(id)} + params := multisig4.TxnIDParams{ID: multisig4.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) diff --git a/chain/actors/builtin/multisig/message4.go b/chain/actors/builtin/multisig/message4.go new file mode 100644 index 000000000..90885aa07 --- /dev/null +++ b/chain/actors/builtin/multisig/message4.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" + + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" + init4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/init" + multisig4 "github.com/filecoin-project/specs-actors/v4/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 message4 struct{ message0 } + +func (m message4) 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 := &multisig4.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 := &init4.ExecParams{ + CodeCID: builtin4.MultisigActorCodeID, + ConstructorParams: enc, + } + + enc, actErr = actors.SerializeParams(execParams) + if actErr != nil { + return nil, actErr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Method: builtin4.MethodsInit.Exec, + Params: enc, + Value: initialAmount, + }, nil +} diff --git a/chain/actors/builtin/multisig/state.go b/chain/actors/builtin/multisig/state.go index 5f9fb6a52..0ce10d290 100644 --- a/chain/actors/builtin/multisig/state.go +++ b/chain/actors/builtin/multisig/state.go @@ -13,6 +13,7 @@ import ( msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -29,6 +30,9 @@ func init() { builtin.RegisterActorState(builtin3.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load3(store, root) }) + builtin.RegisterActorState(builtin4.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load4(store, root) + }) } func Load(store adt.Store, act *types.Actor) (State, error) { @@ -39,6 +43,8 @@ func Load(store adt.Store, act *types.Actor) (State, error) { return load2(store, act.Head) case builtin3.MultisigActorCodeID: return load3(store, act.Head) + case builtin4.MultisigActorCodeID: + return load4(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/multisig/state4.go b/chain/actors/builtin/multisig/state4.go new file mode 100644 index 000000000..3475ad361 --- /dev/null +++ b/chain/actors/builtin/multisig/state4.go @@ -0,0 +1,95 @@ +package multisig + +import ( + "bytes" + "encoding/binary" + + adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" + + "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" + + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" + msig4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/multisig" +) + +var _ State = (*state4)(nil) + +func load4(store adt.Store, root cid.Cid) (State, error) { + out := state4{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state4 struct { + msig4.State + store adt.Store +} + +func (s *state4) LockedBalance(currEpoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.State.AmountLocked(currEpoch - s.State.StartEpoch), nil +} + +func (s *state4) StartEpoch() (abi.ChainEpoch, error) { + return s.State.StartEpoch, nil +} + +func (s *state4) UnlockDuration() (abi.ChainEpoch, error) { + return s.State.UnlockDuration, nil +} + +func (s *state4) InitialBalance() (abi.TokenAmount, error) { + return s.State.InitialBalance, nil +} + +func (s *state4) Threshold() (uint64, error) { + return s.State.NumApprovalsThreshold, nil +} + +func (s *state4) Signers() ([]address.Address, error) { + return s.State.Signers, nil +} + +func (s *state4) ForEachPendingTxn(cb func(id int64, txn Transaction) error) error { + arr, err := adt4.AsMap(s.store, s.State.PendingTxns, builtin4.DefaultHamtBitwidth) + if err != nil { + return err + } + var out msig4.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)) + }) +} + +func (s *state4) PendingTxnChanged(other State) (bool, error) { + other2, ok := other.(*state4) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.PendingTxns.Equals(other2.PendingTxns), nil +} + +func (s *state4) transactions() (adt.Map, error) { + return adt4.AsMap(s.store, s.PendingTxns, builtin4.DefaultHamtBitwidth) +} + +func (s *state4) decodeTransaction(val *cbg.Deferred) (Transaction, error) { + var tx msig4.Transaction + if err := tx.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return Transaction{}, err + } + return tx, nil +} diff --git a/chain/actors/builtin/paych/message.go b/chain/actors/builtin/paych/message.go index 39c091d45..6669cd227 100644 --- a/chain/actors/builtin/paych/message.go +++ b/chain/actors/builtin/paych/message.go @@ -8,10 +8,10 @@ import ( "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" - builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" ) -var Methods = builtin3.MethodsPaych +var Methods = builtin4.MethodsPaych func Message(version actors.Version, from address.Address) MessageBuilder { switch version { @@ -21,6 +21,8 @@ func Message(version actors.Version, from address.Address) MessageBuilder { return message2{from} case actors.Version3: return message3{from} + case actors.Version4: + return message4{from} default: panic(fmt.Sprintf("unsupported actors version: %d", version)) } diff --git a/chain/actors/builtin/paych/message4.go b/chain/actors/builtin/paych/message4.go new file mode 100644 index 000000000..b2c6b612e --- /dev/null +++ b/chain/actors/builtin/paych/message4.go @@ -0,0 +1,74 @@ +package paych + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" + init4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/init" + paych4 "github.com/filecoin-project/specs-actors/v4/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 message4 struct{ from address.Address } + +func (m message4) Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error) { + params, aerr := actors.SerializeParams(&paych4.ConstructorParams{From: m.from, To: to}) + if aerr != nil { + return nil, aerr + } + enc, aerr := actors.SerializeParams(&init4.ExecParams{ + CodeCID: builtin4.PaymentChannelActorCodeID, + ConstructorParams: params, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Value: initialAmount, + Method: builtin4.MethodsInit.Exec, + Params: enc, + }, nil +} + +func (m message4) Update(paych address.Address, sv *SignedVoucher, secret []byte) (*types.Message, error) { + params, aerr := actors.SerializeParams(&paych4.UpdateChannelStateParams{ + Sv: *sv, + Secret: secret, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin4.MethodsPaych.UpdateChannelState, + Params: params, + }, nil +} + +func (m message4) Settle(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin4.MethodsPaych.Settle, + }, nil +} + +func (m message4) Collect(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin4.MethodsPaych.Collect, + }, nil +} diff --git a/chain/actors/builtin/paych/state.go b/chain/actors/builtin/paych/state.go index accb96244..f28dc2f83 100644 --- a/chain/actors/builtin/paych/state.go +++ b/chain/actors/builtin/paych/state.go @@ -16,6 +16,7 @@ import ( paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -32,6 +33,9 @@ func init() { builtin.RegisterActorState(builtin3.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load3(store, root) }) + builtin.RegisterActorState(builtin4.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load4(store, root) + }) } // Load returns an abstract copy of payment channel state, irregardless of actor version @@ -43,6 +47,8 @@ func Load(store adt.Store, act *types.Actor) (State, error) { return load2(store, act.Head) case builtin3.PaymentChannelActorCodeID: return load3(store, act.Head) + case builtin4.PaymentChannelActorCodeID: + return load4(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/paych/state4.go b/chain/actors/builtin/paych/state4.go new file mode 100644 index 000000000..cf37eea5c --- /dev/null +++ b/chain/actors/builtin/paych/state4.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" + + paych4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/paych" + adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" +) + +var _ State = (*state4)(nil) + +func load4(store adt.Store, root cid.Cid) (State, error) { + out := state4{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state4 struct { + paych4.State + store adt.Store + lsAmt *adt4.Array +} + +// Channel owner, who has funded the actor +func (s *state4) From() (address.Address, error) { + return s.State.From, nil +} + +// Recipient of payouts from channel +func (s *state4) To() (address.Address, error) { + return s.State.To, nil +} + +// Height at which the channel can be `Collected` +func (s *state4) SettlingAt() (abi.ChainEpoch, error) { + return s.State.SettlingAt, nil +} + +// Amount successfully redeemed through the payment channel, paid out on `Collect()` +func (s *state4) ToSend() (abi.TokenAmount, error) { + return s.State.ToSend, nil +} + +func (s *state4) getOrLoadLsAmt() (*adt4.Array, error) { + if s.lsAmt != nil { + return s.lsAmt, nil + } + + // Get the lane state from the chain + lsamt, err := adt4.AsArray(s.store, s.State.LaneStates, paych4.LaneStatesAmtBitwidth) + if err != nil { + return nil, err + } + + s.lsAmt = lsamt + return lsamt, nil +} + +// Get total number of lanes +func (s *state4) LaneCount() (uint64, error) { + lsamt, err := s.getOrLoadLsAmt() + if err != nil { + return 0, err + } + return lsamt.Length(), nil +} + +// Iterate lane states +func (s *state4) 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 paych4.LaneState + return lsamt.ForEach(&ls, func(i int64) error { + return cb(uint64(i), &laneState4{ls}) + }) +} + +type laneState4 struct { + paych4.LaneState +} + +func (ls *laneState4) Redeemed() (big.Int, error) { + return ls.LaneState.Redeemed, nil +} + +func (ls *laneState4) 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 712fb0b98..7e15275a5 100644 --- a/chain/actors/builtin/power/power.go +++ b/chain/actors/builtin/power/power.go @@ -17,6 +17,7 @@ import ( builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" ) func init() { @@ -29,11 +30,14 @@ func init() { builtin.RegisterActorState(builtin3.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load3(store, root) }) + builtin.RegisterActorState(builtin4.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load4(store, root) + }) } var ( - Address = builtin3.StoragePowerActorAddr - Methods = builtin3.MethodsPower + Address = builtin4.StoragePowerActorAddr + Methods = builtin4.MethodsPower ) func Load(store adt.Store, act *types.Actor) (st State, err error) { @@ -44,6 +48,8 @@ func Load(store adt.Store, act *types.Actor) (st State, err error) { return load2(store, act.Head) case builtin3.StoragePowerActorCodeID: return load3(store, act.Head) + case builtin4.StoragePowerActorCodeID: + return load4(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/power/v4.go b/chain/actors/builtin/power/v4.go new file mode 100644 index 000000000..bae5d044e --- /dev/null +++ b/chain/actors/builtin/power/v4.go @@ -0,0 +1,149 @@ +package power + +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/actors/builtin" + + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" + power4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/power" + adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" +) + +var _ State = (*state4)(nil) + +func load4(store adt.Store, root cid.Cid) (State, error) { + out := state4{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state4 struct { + power4.State + store adt.Store +} + +func (s *state4) TotalLocked() (abi.TokenAmount, error) { + return s.TotalPledgeCollateral, nil +} + +func (s *state4) 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 *state4) TotalCommitted() (Claim, error) { + return Claim{ + RawBytePower: s.TotalBytesCommitted, + QualityAdjPower: s.TotalQABytesCommitted, + }, nil +} + +func (s *state4) MinerPower(addr address.Address) (Claim, bool, error) { + claims, err := s.claims() + if err != nil { + return Claim{}, false, err + } + var claim power4.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 *state4) MinerNominalPowerMeetsConsensusMinimum(a address.Address) (bool, error) { + return s.State.MinerNominalPowerMeetsConsensusMinimum(s.store, a) +} + +func (s *state4) TotalPowerSmoothed() (builtin.FilterEstimate, error) { + return builtin.FromV4FilterEstimate(s.State.ThisEpochQAPowerSmoothed), nil +} + +func (s *state4) MinerCounts() (uint64, uint64, error) { + return uint64(s.State.MinerAboveMinPowerCount), uint64(s.State.MinerCount), nil +} + +func (s *state4) ListAllMiners() ([]address.Address, error) { + claims, err := 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 +} + +func (s *state4) ForEachClaim(cb func(miner address.Address, claim Claim) error) error { + claims, err := s.claims() + if err != nil { + return err + } + + var claim power4.Claim + return claims.ForEach(&claim, func(k string) error { + a, err := address.NewFromBytes([]byte(k)) + if err != nil { + return err + } + return cb(a, Claim{ + RawBytePower: claim.RawBytePower, + QualityAdjPower: claim.QualityAdjPower, + }) + }) +} + +func (s *state4) ClaimsChanged(other State) (bool, error) { + other2, ok := other.(*state4) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.Claims.Equals(other2.State.Claims), nil +} + +func (s *state4) claims() (adt.Map, error) { + return adt4.AsMap(s.store, s.Claims, builtin4.DefaultHamtBitwidth) +} + +func (s *state4) decodeClaim(val *cbg.Deferred) (Claim, error) { + var ci power4.Claim + if err := ci.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return Claim{}, err + } + return fromV4Claim(ci), nil +} + +func fromV4Claim(v4 power4.Claim) Claim { + return Claim{ + RawBytePower: v4.RawBytePower, + QualityAdjPower: v4.QualityAdjPower, + } +} diff --git a/chain/actors/builtin/reward/reward.go b/chain/actors/builtin/reward/reward.go index 156b3ec55..cfcd68dd5 100644 --- a/chain/actors/builtin/reward/reward.go +++ b/chain/actors/builtin/reward/reward.go @@ -10,6 +10,7 @@ import ( builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -26,11 +27,14 @@ func init() { builtin.RegisterActorState(builtin3.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load3(store, root) }) + builtin.RegisterActorState(builtin4.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load4(store, root) + }) } var ( - Address = builtin3.RewardActorAddr - Methods = builtin3.MethodsReward + Address = builtin4.RewardActorAddr + Methods = builtin4.MethodsReward ) func Load(store adt.Store, act *types.Actor) (st State, err error) { @@ -41,6 +45,8 @@ func Load(store adt.Store, act *types.Actor) (st State, err error) { return load2(store, act.Head) case builtin3.RewardActorCodeID: return load3(store, act.Head) + case builtin4.RewardActorCodeID: + return load4(store, act.Head) } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } diff --git a/chain/actors/builtin/reward/v4.go b/chain/actors/builtin/reward/v4.go new file mode 100644 index 000000000..7320d1701 --- /dev/null +++ b/chain/actors/builtin/reward/v4.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" + + miner4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" + reward4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/reward" + smoothing4 "github.com/filecoin-project/specs-actors/v4/actors/util/smoothing" +) + +var _ State = (*state4)(nil) + +func load4(store adt.Store, root cid.Cid) (State, error) { + out := state4{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state4 struct { + reward4.State + store adt.Store +} + +func (s *state4) ThisEpochReward() (abi.TokenAmount, error) { + return s.State.ThisEpochReward, nil +} + +func (s *state4) ThisEpochRewardSmoothed() (builtin.FilterEstimate, error) { + return builtin.FilterEstimate{ + PositionEstimate: s.State.ThisEpochRewardSmoothed.PositionEstimate, + VelocityEstimate: s.State.ThisEpochRewardSmoothed.VelocityEstimate, + }, nil +} + +func (s *state4) ThisEpochBaselinePower() (abi.StoragePower, error) { + return s.State.ThisEpochBaselinePower, nil +} + +func (s *state4) TotalStoragePowerReward() (abi.TokenAmount, error) { + return s.State.TotalStoragePowerReward, nil +} + +func (s *state4) EffectiveBaselinePower() (abi.StoragePower, error) { + return s.State.EffectiveBaselinePower, nil +} + +func (s *state4) EffectiveNetworkTime() (abi.ChainEpoch, error) { + return s.State.EffectiveNetworkTime, nil +} + +func (s *state4) CumsumBaseline() (reward4.Spacetime, error) { + return s.State.CumsumBaseline, nil +} + +func (s *state4) CumsumRealized() (reward4.Spacetime, error) { + return s.State.CumsumRealized, nil +} + +func (s *state4) InitialPledgeForPower(qaPower abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) { + return miner4.InitialPledgeForPower( + qaPower, + s.State.ThisEpochBaselinePower, + s.State.ThisEpochRewardSmoothed, + smoothing4.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + circSupply, + ), nil +} + +func (s *state4) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) { + return miner4.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed, + smoothing4.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + sectorWeight), nil +} diff --git a/chain/actors/builtin/verifreg/v4.go b/chain/actors/builtin/verifreg/v4.go new file mode 100644 index 000000000..2419ef758 --- /dev/null +++ b/chain/actors/builtin/verifreg/v4.go @@ -0,0 +1,58 @@ +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" + + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" + verifreg4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/verifreg" + adt4 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" +) + +var _ State = (*state4)(nil) + +func load4(store adt.Store, root cid.Cid) (State, error) { + out := state4{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +type state4 struct { + verifreg4.State + store adt.Store +} + +func (s *state4) RootKey() (address.Address, error) { + return s.State.RootKey, nil +} + +func (s *state4) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, actors.Version4, s.verifiedClients, addr) +} + +func (s *state4) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, actors.Version4, s.verifiers, addr) +} + +func (s *state4) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachCap(s.store, actors.Version4, s.verifiers, cb) +} + +func (s *state4) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachCap(s.store, actors.Version4, s.verifiedClients, cb) +} + +func (s *state4) verifiedClients() (adt.Map, error) { + return adt4.AsMap(s.store, s.VerifiedClients, builtin4.DefaultHamtBitwidth) +} + +func (s *state4) verifiers() (adt.Map, error) { + return adt4.AsMap(s.store, s.Verifiers, builtin4.DefaultHamtBitwidth) +} diff --git a/chain/actors/builtin/verifreg/verifreg.go b/chain/actors/builtin/verifreg/verifreg.go index 4e3f3559b..83ba0c6c5 100644 --- a/chain/actors/builtin/verifreg/verifreg.go +++ b/chain/actors/builtin/verifreg/verifreg.go @@ -1,15 +1,17 @@ package verifreg import ( - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-state-types/abi" - builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" "github.com/ipfs/go-cid" "golang.org/x/xerrors" + "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" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -26,11 +28,14 @@ func init() { builtin.RegisterActorState(builtin3.VerifiedRegistryActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load3(store, root) }) + builtin.RegisterActorState(builtin4.VerifiedRegistryActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load4(store, root) + }) } var ( - Address = builtin3.VerifiedRegistryActorAddr - Methods = builtin3.MethodsVerifiedRegistry + Address = builtin4.VerifiedRegistryActorAddr + Methods = builtin4.MethodsVerifiedRegistry ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -41,6 +46,8 @@ func Load(store adt.Store, act *types.Actor) (State, error) { return load2(store, act.Head) case builtin3.VerifiedRegistryActorCodeID: return load3(store, act.Head) + case builtin4.VerifiedRegistryActorCodeID: + return load4(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 6b27238da..01c4b14d2 100644 --- a/chain/actors/policy/policy.go +++ b/chain/actors/policy/policy.go @@ -20,15 +20,20 @@ import ( builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" market3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/market" miner3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/miner" - paych3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/paych" verifreg3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/verifreg" + + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" + market4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/market" + miner4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" + paych4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/paych" + verifreg4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/verifreg" ) const ( - ChainFinality = miner3.ChainFinality - SealRandomnessLookback = ChainFinality - PaychSettleDelay = paych3.SettleDelay - MaxPreCommitRandomnessLookback = builtin3.EpochsInDay + SealRandomnessLookback + ChainFinality = miner4.ChainFinality + SealRandomnessLookback = ChainFinality + PaychSettleDelay = paych4.SettleDelay + MaxPreCommitRandomnessLookback = builtin4.EpochsInDay + SealRandomnessLookback ) // SetSupportedProofTypes sets supported proof types, across all actor versions. @@ -43,6 +48,10 @@ func SetSupportedProofTypes(types ...abi.RegisteredSealProof) { miner3.PreCommitSealProofTypesV7 = make(map[abi.RegisteredSealProof]struct{}, len(types)*2) miner3.PreCommitSealProofTypesV8 = make(map[abi.RegisteredSealProof]struct{}, len(types)) + miner4.PreCommitSealProofTypesV0 = make(map[abi.RegisteredSealProof]struct{}, len(types)) + miner4.PreCommitSealProofTypesV7 = make(map[abi.RegisteredSealProof]struct{}, len(types)*2) + miner4.PreCommitSealProofTypesV8 = make(map[abi.RegisteredSealProof]struct{}, len(types)) + AddSupportedProofTypes(types...) } @@ -55,19 +64,21 @@ func AddSupportedProofTypes(types ...abi.RegisteredSealProof) { } // Set for all miner versions. miner0.SupportedProofTypes[t] = struct{}{} - miner2.PreCommitSealProofTypesV0[t] = struct{}{} + miner2.PreCommitSealProofTypesV0[t] = struct{}{} miner2.PreCommitSealProofTypesV7[t] = struct{}{} miner2.PreCommitSealProofTypesV7[t+abi.RegisteredSealProof_StackedDrg2KiBV1_1] = struct{}{} - miner2.PreCommitSealProofTypesV8[t+abi.RegisteredSealProof_StackedDrg2KiBV1_1] = struct{}{} miner3.PreCommitSealProofTypesV0[t] = struct{}{} - miner3.PreCommitSealProofTypesV7[t] = struct{}{} miner3.PreCommitSealProofTypesV7[t+abi.RegisteredSealProof_StackedDrg2KiBV1_1] = struct{}{} - miner3.PreCommitSealProofTypesV8[t+abi.RegisteredSealProof_StackedDrg2KiBV1_1] = struct{}{} + + miner4.PreCommitSealProofTypesV0[t] = struct{}{} + miner4.PreCommitSealProofTypesV7[t] = struct{}{} + miner4.PreCommitSealProofTypesV7[t+abi.RegisteredSealProof_StackedDrg2KiBV1_1] = struct{}{} + miner4.PreCommitSealProofTypesV8[t+abi.RegisteredSealProof_StackedDrg2KiBV1_1] = struct{}{} } } @@ -78,6 +89,7 @@ func SetPreCommitChallengeDelay(delay abi.ChainEpoch) { miner0.PreCommitChallengeDelay = delay miner2.PreCommitChallengeDelay = delay miner3.PreCommitChallengeDelay = delay + miner4.PreCommitChallengeDelay = delay } // TODO: this function shouldn't really exist. Instead, the API should expose the precommit delay. @@ -97,6 +109,10 @@ func SetConsensusMinerMinPower(p abi.StoragePower) { for _, policy := range builtin3.PoStProofPolicies { policy.ConsensusMinerMinPower = p } + + for _, policy := range builtin4.PoStProofPolicies { + policy.ConsensusMinerMinPower = p + } } // SetMinVerifiedDealSize sets the minimum size of a verified deal. This should @@ -105,6 +121,7 @@ func SetMinVerifiedDealSize(size abi.StoragePower) { verifreg0.MinVerifiedDealSize = size verifreg2.MinVerifiedDealSize = size verifreg3.MinVerifiedDealSize = size + verifreg4.MinVerifiedDealSize = size } func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) abi.ChainEpoch { @@ -115,6 +132,8 @@ func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) ab return miner2.MaxProveCommitDuration[t] case actors.Version3: return miner3.MaxProveCommitDuration[t] + case actors.Version4: + return miner4.MaxProveCommitDuration[t] default: panic("unsupported actors version") } @@ -132,6 +151,8 @@ func DealProviderCollateralBounds( return market2.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil) case actors.Version3: return market3.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil) + case actors.Version4: + return market4.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil) default: panic("unsupported actors version") } @@ -155,6 +176,10 @@ func SetWPoStChallengeWindow(period abi.ChainEpoch) { // by default, this is 2x finality which is 30 periods. // scale it if we're scaling the challenge period. miner3.WPoStDisputeWindow = period * 30 + + miner4.WPoStChallengeWindow = period + miner4.WPoStProvingPeriod = period * abi.ChainEpoch(miner4.WPoStPeriodDeadlines) + miner4.WPoStDisputeWindow = period * 30 // see the miner3 comment } func GetWinningPoStSectorSetLookback(nwVer network.Version) abi.ChainEpoch { @@ -175,13 +200,13 @@ func GetMaxPoStPartitions(p abi.RegisteredPoStProof) (int, error) { if err != nil { return 0, err } - return int(miner3.AddressedSectorsMax / sectorsPerPart), nil + return int(miner4.AddressedSectorsMax / sectorsPerPart), nil } func GetDefaultSectorSize() abi.SectorSize { // supported sector sizes are the same across versions. - szs := make([]abi.SectorSize, 0, len(miner3.PreCommitSealProofTypesV8)) - for spt := range miner3.PreCommitSealProofTypesV8 { + szs := make([]abi.SectorSize, 0, len(miner4.PreCommitSealProofTypesV8)) + for spt := range miner4.PreCommitSealProofTypesV8 { ss, err := spt.SectorSize() if err != nil { panic(err) @@ -199,10 +224,10 @@ func GetDefaultSectorSize() abi.SectorSize { func GetSectorMaxLifetime(proof abi.RegisteredSealProof, nwVer network.Version) abi.ChainEpoch { if nwVer <= network.Version10 { - return builtin3.SealProofPoliciesV0[proof].SectorMaxLifetime + return builtin4.SealProofPoliciesV0[proof].SectorMaxLifetime } - return builtin3.SealProofPoliciesV11[proof].SectorMaxLifetime + return builtin4.SealProofPoliciesV11[proof].SectorMaxLifetime } func GetAddressedSectorsMax(nwVer network.Version) int { @@ -213,6 +238,8 @@ func GetAddressedSectorsMax(nwVer network.Version) int { return miner2.AddressedSectorsMax case actors.Version3: return miner3.AddressedSectorsMax + case actors.Version4: + return miner4.AddressedSectorsMax default: panic("unsupported network version") } @@ -227,6 +254,8 @@ func GetDeclarationsMax(nwVer network.Version) int { return miner2.DeclarationsMax case actors.Version3: return miner3.DeclarationsMax + case actors.Version4: + return miner4.DeclarationsMax default: panic("unsupported network version") } diff --git a/chain/actors/version.go b/chain/actors/version.go index d62fd0d17..bd7b708bd 100644 --- a/chain/actors/version.go +++ b/chain/actors/version.go @@ -12,6 +12,7 @@ const ( Version0 Version = 0 Version2 Version = 2 Version3 Version = 3 + Version4 Version = 4 ) // Converts a network version into an actors adt version. @@ -23,6 +24,8 @@ func VersionForNetwork(version network.Version) Version { return Version2 case network.Version10, network.Version11: return Version3 + case network.Version12: + return Version4 default: panic(fmt.Sprintf("unsupported network version %d", version)) } diff --git a/chain/beacon/drand/drand.go b/chain/beacon/drand/drand.go index cb08b6af9..847091858 100644 --- a/chain/beacon/drand/drand.go +++ b/chain/beacon/drand/drand.go @@ -3,7 +3,6 @@ package drand import ( "bytes" "context" - "sync" "time" dchain "github.com/drand/drand/chain" @@ -13,6 +12,7 @@ import ( gclient "github.com/drand/drand/lp2p/client" "github.com/drand/kyber" kzap "github.com/go-kit/kit/log/zap" + lru "github.com/hashicorp/golang-lru" "go.uber.org/zap/zapcore" "golang.org/x/xerrors" @@ -61,8 +61,7 @@ type DrandBeacon struct { filGenTime uint64 filRoundTime uint64 - cacheLk sync.Mutex - localCache map[uint64]types.BeaconEntry + localCache *lru.Cache } // DrandHTTPClient interface overrides the user agent used by drand @@ -111,9 +110,14 @@ func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub, config dtypes return nil, xerrors.Errorf("creating drand client") } + lc, err := lru.New(1024) + if err != nil { + return nil, err + } + db := &DrandBeacon{ client: client, - localCache: make(map[uint64]types.BeaconEntry), + localCache: lc, } db.pubkey = drandChain.PublicKey @@ -156,19 +160,16 @@ func (db *DrandBeacon) Entry(ctx context.Context, round uint64) <-chan beacon.Re return out } func (db *DrandBeacon) cacheValue(e types.BeaconEntry) { - db.cacheLk.Lock() - defer db.cacheLk.Unlock() - db.localCache[e.Round] = e + db.localCache.Add(e.Round, e) } func (db *DrandBeacon) getCachedValue(round uint64) *types.BeaconEntry { - db.cacheLk.Lock() - defer db.cacheLk.Unlock() - v, ok := db.localCache[round] + v, ok := db.localCache.Get(round) if !ok { return nil } - return &v + e, _ := v.(*types.BeaconEntry) + return e } func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntry) error { diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 26b9845fc..0a836804f 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -11,7 +11,9 @@ import ( "github.com/filecoin-project/go-address" tbig "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/specs-actors/v3/actors/builtin" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/types" @@ -698,6 +700,17 @@ func (*MessagePool) getGasPerf(gasReward *big.Int, gasLimit int64) float64 { return r } +func isMessageMute(m *types.Message, ts *types.TipSet) bool { + if api.RunningNodeType != api.NodeFull || ts.Height() > build.UpgradeActorsV4Height { + return false + } + + if m.To == builtin.StoragePowerActorAddr { + return m.Method == builtin.MethodsPower.CreateMiner + } + return false +} + func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint64]*types.SignedMessage, baseFee types.BigInt, ts *types.TipSet) []*msgChain { // collect all messages msgs := make([]*types.SignedMessage, 0, len(mset)) @@ -758,6 +771,11 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6 if balance.Cmp(required) < 0 { break } + + if isMessageMute(&m.Message, ts) { + break + } + balance = new(big.Int).Sub(balance, required) value := m.Message.Value.Int diff --git a/chain/state/statetree.go b/chain/state/statetree.go index 46a13ccc6..33a8116df 100644 --- a/chain/state/statetree.go +++ b/chain/state/statetree.go @@ -24,6 +24,7 @@ import ( states0 "github.com/filecoin-project/specs-actors/actors/states" states2 "github.com/filecoin-project/specs-actors/v2/actors/states" states3 "github.com/filecoin-project/specs-actors/v3/actors/states" + states4 "github.com/filecoin-project/specs-actors/v4/actors/states" ) var log = logging.Logger("statetree") @@ -184,6 +185,12 @@ func NewStateTree(cst cbor.IpldStore, ver types.StateTreeVersion) (*StateTree, e return nil, xerrors.Errorf("failed to create state tree: %w", err) } hamt = tree.Map + case types.StateTreeVersion3: + tree, err := states4.NewTree(store) + if err != nil { + return nil, xerrors.Errorf("failed to create state tree: %w", err) + } + hamt = tree.Map default: return nil, xerrors.Errorf("unsupported state tree version: %d", ver) } @@ -233,6 +240,12 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) { if tree != nil { hamt = tree.Map } + case types.StateTreeVersion3: + var tree *states4.Tree + tree, err = states4.LoadTree(store, root.Actors) + if tree != nil { + hamt = tree.Map + } default: return nil, xerrors.Errorf("unsupported state tree version: %d", root.Version) } diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index ce140868e..a7b56f679 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -34,6 +34,7 @@ import ( "github.com/filecoin-project/specs-actors/v2/actors/migration/nv4" "github.com/filecoin-project/specs-actors/v2/actors/migration/nv7" "github.com/filecoin-project/specs-actors/v3/actors/migration/nv10" + "github.com/filecoin-project/specs-actors/v4/actors/migration/nv12" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" "golang.org/x/xerrors" @@ -190,6 +191,22 @@ func DefaultUpgradeSchedule() UpgradeSchedule { Height: build.UpgradeNorwegianHeight, Network: network.Version11, Migration: nil, + }, { + Height: build.UpgradeActorsV4Height, + Network: network.Version12, + Migration: UpgradeActorsV4, + PreMigrations: []PreMigration{{ + PreMigration: PreUpgradeActorsV4, + StartWithin: 120, + DontStartWithin: 60, + StopWithin: 35, + }, { + PreMigration: PreUpgradeActorsV4, + StartWithin: 30, + DontStartWithin: 15, + StopWithin: 5, + }}, + Expensive: true, }} for _, u := range updates { @@ -1063,6 +1080,92 @@ func upgradeActorsV3Common( return newRoot, nil } +func UpgradeActorsV4(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { + // Use all the CPUs except 3. + workerCount := runtime.NumCPU() - 3 + if workerCount <= 0 { + workerCount = 1 + } + + config := nv12.Config{ + MaxWorkers: uint(workerCount), + JobQueueSize: 1000, + ResultQueueSize: 100, + ProgressLogPeriod: 10 * time.Second, + } + + newRoot, err := upgradeActorsV4Common(ctx, sm, cache, root, epoch, ts, config) + if err != nil { + return cid.Undef, xerrors.Errorf("migrating actors v4 state: %w", err) + } + + return newRoot, nil +} + +func PreUpgradeActorsV4(ctx context.Context, sm *StateManager, cache MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error { + // Use half the CPUs for pre-migration, but leave at least 3. + workerCount := runtime.NumCPU() + if workerCount <= 4 { + workerCount = 1 + } else { + workerCount /= 2 + } + config := nv12.Config{MaxWorkers: uint(workerCount)} + _, err := upgradeActorsV4Common(ctx, sm, cache, root, epoch, ts, config) + return err +} + +func upgradeActorsV4Common( + ctx context.Context, sm *StateManager, cache MigrationCache, + root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet, + config nv12.Config, +) (cid.Cid, error) { + buf := blockstore.NewTieredBstore(sm.cs.StateBlockstore(), blockstore.NewMemorySync()) + store := store.ActorStore(ctx, buf) + + // Load the state root. + var stateRoot types.StateRoot + if err := store.Get(ctx, root, &stateRoot); err != nil { + return cid.Undef, xerrors.Errorf("failed to decode state root: %w", err) + } + + if stateRoot.Version != types.StateTreeVersion2 { + return cid.Undef, xerrors.Errorf( + "expected state root version 2 for actors v4 upgrade, got %d", + stateRoot.Version, + ) + } + + // Perform the migration + newHamtRoot, err := nv12.MigrateStateTree(ctx, store, stateRoot.Actors, epoch, config, migrationLogger{}, cache) + if err != nil { + return cid.Undef, xerrors.Errorf("upgrading to actors v2: %w", err) + } + + // Persist the result. + newRoot, err := store.Put(ctx, &types.StateRoot{ + Version: types.StateTreeVersion3, + Actors: newHamtRoot, + Info: stateRoot.Info, + }) + if err != nil { + return cid.Undef, xerrors.Errorf("failed to persist new state root: %w", err) + } + + // Persist the new tree. + + { + from := buf + to := buf.Read() + + if err := vm.Copy(ctx, from, to, newRoot); err != nil { + return cid.Undef, xerrors.Errorf("copying migrated tree: %w", err) + } + } + + return newRoot, nil +} + func setNetworkName(ctx context.Context, store adt.Store, tree *state.StateTree, name string) error { ia, err := tree.GetActor(builtin0.InitActorAddr) if err != nil { diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 947310c75..be4b9cd4f 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -26,6 +26,7 @@ import ( exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported" exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported" exported3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/exported" + exported4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/exported" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -548,6 +549,7 @@ func init() { actors = append(actors, exported0.BuiltinActors()...) actors = append(actors, exported2.BuiltinActors()...) actors = append(actors, exported3.BuiltinActors()...) + actors = append(actors, exported4.BuiltinActors()...) for _, actor := range actors { exports := actor.Exports() diff --git a/chain/types/state.go b/chain/types/state.go index c14836ee7..b561aab71 100644 --- a/chain/types/state.go +++ b/chain/types/state.go @@ -11,8 +11,10 @@ const ( StateTreeVersion0 StateTreeVersion = iota // StateTreeVersion1 corresponds to actors v2 StateTreeVersion1 - // StateTreeVersion2 corresponds to actors >= v3. + // StateTreeVersion2 corresponds to actors v3. StateTreeVersion2 + // StateTreeVersion3 corresponds to actors >= v4. + StateTreeVersion3 ) type StateRoot struct { diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 1c1d04f19..8e0e6edd6 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -18,6 +18,7 @@ import ( exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported" vmr "github.com/filecoin-project/specs-actors/v2/actors/runtime" exported3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/exported" + exported4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/exported" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/exitcode" @@ -64,6 +65,7 @@ func NewActorRegistry() *ActorRegistry { inv.Register(ActorsVersionPredicate(actors.Version0), exported0.BuiltinActors()...) inv.Register(ActorsVersionPredicate(actors.Version2), exported2.BuiltinActors()...) inv.Register(ActorsVersionPredicate(actors.Version3), exported3.BuiltinActors()...) + inv.Register(ActorsVersionPredicate(actors.Version4), exported4.BuiltinActors()...) return inv } diff --git a/chain/vm/mkactor.go b/chain/vm/mkactor.go index 0e72b0c4b..11de7362b 100644 --- a/chain/vm/mkactor.go +++ b/chain/vm/mkactor.go @@ -17,6 +17,7 @@ import ( builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" + builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/actors/aerrors" @@ -102,6 +103,8 @@ func newAccountActor(ver actors.Version) *types.Actor { code = builtin2.AccountActorCodeID case actors.Version3: code = builtin3.AccountActorCodeID + case actors.Version4: + code = builtin4.AccountActorCodeID default: panic("unsupported actors version") } diff --git a/cmd/lotus-storage-miner/actor_test.go b/cmd/lotus-storage-miner/actor_test.go index 02b41202c..bbe9362d0 100644 --- a/cmd/lotus-storage-miner/actor_test.go +++ b/cmd/lotus-storage-miner/actor_test.go @@ -51,7 +51,7 @@ func TestWorkerKeyChange(t *testing.T) { blocktime := 1 * time.Millisecond - n, sn := builder.MockSbBuilder(t, []test.FullNodeOpts{test.FullNodeWithActorsV3At(2), test.FullNodeWithActorsV3At(2)}, test.OneMiner) + n, sn := builder.MockSbBuilder(t, []test.FullNodeOpts{test.FullNodeWithActorsV4At(-1), test.FullNodeWithActorsV4At(-1)}, test.OneMiner) client1 := n[0] client2 := n[1] diff --git a/documentation/en/api-methods-miner.md b/documentation/en/api-methods-miner.md index 9d33a55d0..d140d7d85 100644 --- a/documentation/en/api-methods-miner.md +++ b/documentation/en/api-methods-miner.md @@ -193,7 +193,7 @@ Response: ```json { "Version": "string value", - "APIVersion": 65792, + "APIVersion": 66048, "BlockDelay": 42 } ``` diff --git a/documentation/en/api-methods-worker.md b/documentation/en/api-methods-worker.md index 40300866e..ddbc6e7f4 100644 --- a/documentation/en/api-methods-worker.md +++ b/documentation/en/api-methods-worker.md @@ -145,7 +145,7 @@ Perms: admin Inputs: `null` -Response: `65792` +Response: `66048` ## Add diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index a3b956ee7..493fd7d2b 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -276,7 +276,7 @@ Response: ```json { "Version": "string value", - "APIVersion": 65792, + "APIVersion": 66048, "BlockDelay": 42 } ``` diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index 76f6dadaf..ae7d54985 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -27,6 +27,7 @@ var log = logging.Logger("sbmock") type SectorMgr struct { sectors map[abi.SectorID]*sectorState + failPoSt bool pieces map[cid.Cid][]byte nextSectorID abi.SectorNumber @@ -263,6 +264,14 @@ func (mgr *SectorMgr) MarkFailed(sid storage.SectorRef, failed bool) error { return nil } +func (mgr *SectorMgr) Fail() { + mgr.lk.Lock() + defer mgr.lk.Unlock() + mgr.failPoSt = true + + return +} + func (mgr *SectorMgr) MarkCorrupted(sid storage.SectorRef, corrupted bool) error { mgr.lk.Lock() defer mgr.lk.Unlock() @@ -292,10 +301,20 @@ func AddOpFinish(ctx context.Context) (context.Context, func()) { } func (mgr *SectorMgr) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof2.SectorInfo, randomness abi.PoStRandomness) ([]proof2.PoStProof, error) { + mgr.lk.Lock() + defer mgr.lk.Unlock() + return generateFakePoSt(sectorInfo, abi.RegisteredSealProof.RegisteredWinningPoStProof, randomness), nil } func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof2.SectorInfo, randomness abi.PoStRandomness) ([]proof2.PoStProof, []abi.SectorID, error) { + mgr.lk.Lock() + defer mgr.lk.Unlock() + + if mgr.failPoSt { + return nil, nil, xerrors.Errorf("failed to post (mock)") + } + si := make([]proof2.SectorInfo, 0, len(sectorInfo)) var skipped []abi.SectorID diff --git a/go.mod b/go.mod index 2d79cdd24..86e6da40d 100644 --- a/go.mod +++ b/go.mod @@ -46,6 +46,7 @@ require ( github.com/filecoin-project/specs-actors v0.9.13 github.com/filecoin-project/specs-actors/v2 v2.3.5-0.20210114162132-5b58b773f4fb github.com/filecoin-project/specs-actors/v3 v3.1.0 + github.com/filecoin-project/specs-actors/v4 v4.0.0 github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 diff --git a/go.sum b/go.sum index c5c4ece4c..8bcfafdfc 100644 --- a/go.sum +++ b/go.sum @@ -312,6 +312,8 @@ github.com/filecoin-project/specs-actors/v2 v2.3.5-0.20210114162132-5b58b773f4fb github.com/filecoin-project/specs-actors/v2 v2.3.5-0.20210114162132-5b58b773f4fb/go.mod h1:LljnY2Mn2homxZsmokJZCpRuhOPxfXhvcek5gWkmqAc= github.com/filecoin-project/specs-actors/v3 v3.1.0 h1:s4qiPw8pgypqBGAy853u/zdZJ7K9cTZdM1rTiSonHrg= github.com/filecoin-project/specs-actors/v3 v3.1.0/go.mod h1:mpynccOLlIRy0QnR008BwYBwT9fen+sPR13MA1VmMww= +github.com/filecoin-project/specs-actors/v4 v4.0.0 h1:vMALksY5G3J5rj3q9rbcyB+f4Tk1xrLqSgdB3jOok4s= +github.com/filecoin-project/specs-actors/v4 v4.0.0/go.mod h1:TkHXf/l7Wyw4ZejyXIPS2rK8bBO0rdwhTZyQQgaglng= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= diff --git a/lotuspond/front/src/chain/methods.json b/lotuspond/front/src/chain/methods.json index b3bc1aa7c..a09d3ec91 100644 --- a/lotuspond/front/src/chain/methods.json +++ b/lotuspond/front/src/chain/methods.json @@ -306,5 +306,109 @@ "AddVerifiedClient", "UseBytes", "RestoreBytes" + ], + "fil/4/account": [ + "Send", + "Constructor", + "PubkeyAddress" + ], + "fil/4/cron": [ + "Send", + "Constructor", + "EpochTick" + ], + "fil/4/init": [ + "Send", + "Constructor", + "Exec" + ], + "fil/4/multisig": [ + "Send", + "Constructor", + "Propose", + "Approve", + "Cancel", + "AddSigner", + "RemoveSigner", + "SwapSigner", + "ChangeNumApprovalsThreshold", + "LockBalance" + ], + "fil/4/paymentchannel": [ + "Send", + "Constructor", + "UpdateChannelState", + "Settle", + "Collect" + ], + "fil/4/reward": [ + "Send", + "Constructor", + "AwardBlockReward", + "ThisEpochReward", + "UpdateNetworkKPI" + ], + "fil/4/storagemarket": [ + "Send", + "Constructor", + "AddBalance", + "WithdrawBalance", + "PublishStorageDeals", + "VerifyDealsForActivation", + "ActivateDeals", + "OnMinerSectorsTerminate", + "ComputeDataCommitment", + "CronTick" + ], + "fil/4/storageminer": [ + "Send", + "Constructor", + "ControlAddresses", + "ChangeWorkerAddress", + "ChangePeerID", + "SubmitWindowedPoSt", + "PreCommitSector", + "ProveCommitSector", + "ExtendSectorExpiration", + "TerminateSectors", + "DeclareFaults", + "DeclareFaultsRecovered", + "OnDeferredCronEvent", + "CheckSectorProven", + "ApplyRewards", + "ReportConsensusFault", + "WithdrawBalance", + "ConfirmSectorProofsValid", + "ChangeMultiaddrs", + "CompactPartitions", + "CompactSectorNumbers", + "ConfirmUpdateWorkerKey", + "RepayDebt", + "ChangeOwnerAddress", + "DisputeWindowedPoSt" + ], + "fil/4/storagepower": [ + "Send", + "Constructor", + "CreateMiner", + "UpdateClaimedPower", + "EnrollCronEvent", + "OnEpochTickEnd", + "UpdatePledgeTotal", + "SubmitPoRepForBulkVerify", + "CurrentTotalPower" + ], + "fil/4/system": [ + "Send", + "Constructor" + ], + "fil/4/verifiedregistry": [ + "Send", + "Constructor", + "AddVerifier", + "RemoveVerifier", + "AddVerifiedClient", + "UseBytes", + "RestoreBytes" ] } \ No newline at end of file diff --git a/node/node_test.go b/node/node_test.go index a246ff65b..91348647d 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -232,3 +232,16 @@ func TestWindowPostDisputeFails(t *testing.T) { test.TestWindowPostDisputeFails(t, builder.MockSbBuilder, 2*time.Millisecond) } + +func TestDeadlineToggling(t *testing.T) { + if os.Getenv("LOTUS_TEST_DEADLINE_TOGGLING") != "1" { + t.Skip("this takes a few minutes, set LOTUS_TEST_DEADLINE_TOGGLING=1 to run") + } + logging.SetLogLevel("miner", "ERROR") + logging.SetLogLevel("chainstore", "ERROR") + logging.SetLogLevel("chain", "ERROR") + logging.SetLogLevel("sub", "ERROR") + logging.SetLogLevel("storageminer", "FATAL") + + test.TestDeadlineToggling(t, builder.MockSbBuilder, 2*time.Millisecond) +} diff --git a/node/test/builder.go b/node/test/builder.go index 72a55ab49..cd0ecc55b 100644 --- a/node/test/builder.go +++ b/node/test/builder.go @@ -18,6 +18,7 @@ import ( "github.com/filecoin-project/go-jsonrpc" "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/go-storedcounter" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/client" @@ -26,6 +27,7 @@ import ( "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" "github.com/filecoin-project/lotus/chain/gen" genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" "github.com/filecoin-project/lotus/chain/messagepool" @@ -44,6 +46,7 @@ import ( "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/storage/mockstorage" miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" + power2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/power" "github.com/ipfs/go-datastore" "github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/peer" @@ -151,6 +154,49 @@ func CreateTestStorageNode(ctx context.Context, t *testing.T, waddr address.Addr return test.TestStorageNode{StorageMiner: minerapi, MineOne: mineOne, Stop: stop} } +func storageBuilder(parentNode test.TestNode, mn mocknet.Mocknet, opts node.Option) test.StorageBuilder { + return func(ctx context.Context, t *testing.T, spt abi.RegisteredSealProof, owner address.Address) test.TestStorageNode { + pk, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + + minerPid, err := peer.IDFromPrivateKey(pk) + require.NoError(t, err) + + params, serr := actors.SerializeParams(&power2.CreateMinerParams{ + Owner: owner, + Worker: owner, + SealProofType: spt, + Peer: abi.PeerID(minerPid), + }) + require.NoError(t, serr) + + createStorageMinerMsg := &types.Message{ + To: power.Address, + From: owner, + Value: big.Zero(), + + Method: power.Methods.CreateMiner, + Params: params, + + GasLimit: 0, + GasPremium: big.NewInt(5252), + } + + signed, err := parentNode.MpoolPushMessage(ctx, createStorageMinerMsg, nil) + require.NoError(t, err) + + mw, err := parentNode.StateWaitMsg(ctx, signed.Cid(), build.MessageConfidence) + require.NoError(t, err) + require.Equal(t, exitcode.Ok, mw.Receipt.ExitCode) + + var retval power2.CreateMinerReturn + err = retval.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)) + require.NoError(t, err) + + return CreateTestStorageNode(ctx, t, owner, retval.IDAddress, pk, parentNode, mn, opts) + } +} + func Builder(t *testing.T, fullOpts []test.FullNodeOpts, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) { return mockBuilderOpts(t, fullOpts, storage, false) } @@ -266,6 +312,8 @@ func mockBuilderOpts(t *testing.T, fullOpts []test.FullNodeOpts, storage []test. if rpc { fulls[i] = fullRpc(t, fulls[i]) } + + fulls[i].Stb = storageBuilder(fulls[i], mn, node.Options()) } for i, def := range storage { @@ -432,6 +480,14 @@ func mockSbBuilderOpts(t *testing.T, fullOpts []test.FullNodeOpts, storage []tes if rpc { fulls[i] = fullRpc(t, fulls[i]) } + + fulls[i].Stb = storageBuilder(fulls[i], mn, node.Options( + node.Override(new(sectorstorage.SectorManager), func() (sectorstorage.SectorManager, error) { + return mock.NewMockSectorMgr(nil), nil + }), + node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), + node.Unset(new(*sectorstorage.Manager)), + )) } for i, def := range storage {