diff --git a/.circleci/config.yml b/.circleci/config.yml index c976c087a..c2f937a9d 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: @@ -731,6 +737,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/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..182b6d302 --- /dev/null +++ b/api/test/deadlines.go @@ -0,0 +1,352 @@ +package test + +import ( + "bytes" + "context" + "fmt" + "testing" + "time" + + "github.com/filecoin-project/lotus/api" + + "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, api.LookbackNoLimit, true) + 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, api.LookbackNoLimit, true) + 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 e5edcbe3b..21ebc94b5 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -8,21 +8,22 @@ import ( "testing" "time" - "github.com/filecoin-project/lotus/api/v1api" - "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" + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/v1api" "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" ) @@ -36,11 +37,15 @@ func init() { build.InsecurePoStValidation = true } +type StorageBuilder func(context.Context, *testing.T, abi.RegisteredSealProof, address.Address) TestStorageNode + type TestNode struct { v1api.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 { @@ -57,6 +62,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 @@ -95,6 +102,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 { @@ -113,7 +121,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{{ @@ -122,10 +134,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, }}) }, } @@ -157,6 +172,9 @@ var MineNext = miner.MineReq{ func (ts *testSuite) testVersion(t *testing.T) { lapi.RunningNodeType = lapi.NodeFull + t.Cleanup(func() { + lapi.RunningNodeType = lapi.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 fec7e0d73..1ff9f79b3 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 f419663e6..743170f04 100644 --- a/api/version.go +++ b/api/version.go @@ -54,8 +54,8 @@ func VersionForType(nodeType NodeType) (Version, error) { // semver versions of the rpc api exposed var ( - FullAPIVersion0 = newVer(1, 2, 0) - FullAPIVersion1 = newVer(2, 0, 0) + FullAPIVersion0 = newVer(1, 3, 0) + FullAPIVersion1 = newVer(2, 1, 0) MinerAPIVersion0 = newVer(1, 0, 1) WorkerAPIVersion0 = newVer(1, 0, 0) diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 83e319db5..df2b87f13 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 3797357ba..a3407e7ca 100644 Binary files a/build/openrpc/miner.json.gz and b/build/openrpc/miner.json.gz differ diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index 33b8c5ebe..04d82b39a 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ 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/build/version.go b/build/version.go index 5af3cce39..84f49ead8 100644 --- a/build/version.go +++ b/build/version.go @@ -29,7 +29,7 @@ func buildType() string { } // BuildVersion is the local build version, set by build system -const BuildVersion = "1.7.1-dev" +const BuildVersion = "1.11.0-dev" func UserVersion() string { return BuildVersion + buildType() + CurrentCommit 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..f210b8d94 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 + ChainFinality = miner4.ChainFinality SealRandomnessLookback = ChainFinality - PaychSettleDelay = paych3.SettleDelay - MaxPreCommitRandomnessLookback = builtin3.EpochsInDay + SealRandomnessLookback + 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-v0-methods-miner.md b/documentation/en/api-v0-methods-miner.md index 6f1c076a6..ea5ca75f8 100644 --- a/documentation/en/api-v0-methods-miner.md +++ b/documentation/en/api-v0-methods-miner.md @@ -193,7 +193,7 @@ Response: ```json { "Version": "string value", - "APIVersion": 131072, + "APIVersion": 131328, "BlockDelay": 42 } ``` diff --git a/documentation/en/api-v0-methods-worker.md b/documentation/en/api-v0-methods-worker.md index a697258a4..b0130a2a0 100644 --- a/documentation/en/api-v0-methods-worker.md +++ b/documentation/en/api-v0-methods-worker.md @@ -145,7 +145,7 @@ Perms: admin Inputs: `null` -Response: `131072` +Response: `131328` ## Add diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index e7733b8d5..3c5356a56 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -276,7 +276,7 @@ Response: ```json { "Version": "string value", - "APIVersion": 131072, + "APIVersion": 131328, "BlockDelay": 42 } ``` diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index 63ab75462..261c0d51b 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -273,7 +273,7 @@ Response: ```json { "Version": "string value", - "APIVersion": 131072, + "APIVersion": 131328, "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 497591cde..7e26966a8 100644 --- a/node/test/builder.go +++ b/node/test/builder.go @@ -19,6 +19,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" @@ -29,6 +30,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" @@ -47,6 +49,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" @@ -154,6 +157,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, api.LookbackNoLimit, true) + 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) } @@ -269,6 +315,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 { @@ -435,6 +483,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 {