From 283ada11999ab8a93b8c82973b98e942f1ff135d Mon Sep 17 00:00:00 2001 From: Jakub Sztandera <kubuxu@protocol.ai> Date: Tue, 22 Feb 2022 19:51:26 +0100 Subject: [PATCH 1/4] PreCommitDeposit is now independent of the verified status Deal data is still fetched to check if deals don't occupy more space than the room in the sector. This check can be delayed to ProveCommit. Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai> --- actors/builtin/miner/miner_actor.go | 7 ++---- actors/builtin/miner/miner_commitment_test.go | 22 +++++++------------ actors/builtin/miner/monies.go | 2 -- actors/builtin/miner/policy.go | 7 ++++++ actors/test/commit_post_test.go | 14 ++++++------ support/agent/cases_test.go | 2 +- 6 files changed, 25 insertions(+), 29 deletions(-) diff --git a/actors/builtin/miner/miner_actor.go b/actors/builtin/miner/miner_actor.go index a7c0edefd..f63269f45 100644 --- a/actors/builtin/miner/miner_actor.go +++ b/actors/builtin/miner/miner_actor.go @@ -791,11 +791,8 @@ func (a Actor) PreCommitSectorBatch(rt Runtime, params *PreCommitSectorBatchPara rt.Abortf(exitcode.ErrIllegalArgument, "deals too large to fit in sector %d > %d", dealWeight.DealSpace, info.SectorSize) } - // Estimate the sector weight using the current epoch as an estimate for activation, - // and compute the pre-commit deposit using that weight. - // The sector's power will be recalculated when it's proven. - duration := precommit.Expiration - currEpoch - sectorWeight := QAPowerForWeight(info.SectorSize, duration, dealWeight.DealWeight, dealWeight.VerifiedDealWeight) + // For PreCommitDeposit we estimate maximum possible power of the sector + sectorWeight := QAPowerMax(info.SectorSize) depositReq := PreCommitDepositForPower(rewardStats.ThisEpochRewardSmoothed, pwrTotal.QualityAdjPowerSmoothed, sectorWeight) // Build on-chain record. diff --git a/actors/builtin/miner/miner_commitment_test.go b/actors/builtin/miner/miner_commitment_test.go index 00b15c062..111ebfb61 100644 --- a/actors/builtin/miner/miner_commitment_test.go +++ b/actors/builtin/miner/miner_commitment_test.go @@ -101,7 +101,7 @@ func TestCommitments(t *testing.T) { assert.Equal(t, precommitParams.DealIDs, precommit.Info.DealIDs) assert.Equal(t, precommitParams.Expiration, precommit.Info.Expiration) - pwrEstimate := miner.QAPowerForWeight(actor.sectorSize, precommit.Info.Expiration-precommitEpoch, dealWeight, verifiedDealWeight) + pwrEstimate := miner.QAPowerMax(actor.sectorSize) expectedDeposit := miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, pwrEstimate) assert.Equal(t, expectedDeposit, precommit.PreCommitDeposit) @@ -546,7 +546,7 @@ func TestPreCommitBatch(t *testing.T) { DealWeight: dealWeight, VerifiedDealWeight: verifiedDealWeight, } - pwrEstimate := miner.QAPowerForWeight(actor.sectorSize, sectors[i].Expiration-precommitEpoch, dealWeight, verifiedDealWeight) + pwrEstimate := miner.QAPowerMax(actor.sectorSize) deposits[i] = miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, pwrEstimate) } @@ -583,8 +583,7 @@ func TestPreCommitBatch(t *testing.T) { assert.Equal(t, sectors[i].DealIDs, precommits[i].Info.DealIDs) assert.Equal(t, sectors[i].Expiration, precommits[i].Info.Expiration) - pwrEstimate := miner.QAPowerForWeight(actor.sectorSize, precommits[i].Info.Expiration-precommitEpoch, - conf.sectorWeights[i].DealWeight, conf.sectorWeights[i].VerifiedDealWeight) + pwrEstimate := miner.QAPowerMax(actor.sectorSize) expectedDeposit := miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, pwrEstimate) assert.Equal(t, expectedDeposit, precommits[i].PreCommitDeposit) } @@ -680,8 +679,7 @@ func TestProveCommit(t *testing.T) { assert.Equal(t, dealWeight, precommit.DealWeight) assert.Equal(t, verifiedDealWeight, precommit.VerifiedDealWeight) - pwrEstimate := miner.QAPowerForWeight(actor.sectorSize, precommit.Info.Expiration-precommitEpoch, precommit.DealWeight, precommit.VerifiedDealWeight) - expectedDeposit := miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, pwrEstimate) + expectedDeposit := miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, miner.QAPowerMax(actor.sectorSize)) assert.Equal(t, expectedDeposit, precommit.PreCommitDeposit) // expect total precommit deposit to equal our new deposit @@ -783,14 +781,10 @@ func TestProveCommit(t *testing.T) { dealLifespan := sectorExpiration - proveCommitEpoch verifiedDealWeight := big.Mul(big.NewIntUnsigned(dealSpace), big.NewInt(int64(dealLifespan))) - // Power estimates made a pre-commit time - noDealPowerEstimate := miner.QAPowerForWeight(actor.sectorSize, sectorExpiration-precommitEpoch, big.Zero(), big.Zero()) - fullDealPowerEstimate := miner.QAPowerForWeight(actor.sectorSize, sectorExpiration-precommitEpoch, dealWeight, verifiedDealWeight) - deposits := []big.Int{ - miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, noDealPowerEstimate), - miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, fullDealPowerEstimate), - miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, fullDealPowerEstimate), + miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, miner.QAPowerMax(actor.sectorSize)), + miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, miner.QAPowerMax(actor.sectorSize)), + miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, miner.QAPowerMax(actor.sectorSize)), } conf := preCommitBatchConf{ sectorWeights: []market.SectorWeights{ @@ -1422,7 +1416,7 @@ func TestBatchMethodNetworkFees(t *testing.T) { // Give miner enough balance to pay both and pcd balance := big.Mul(big.NewInt(2), netFee) - oneSectorPowerEstimate := miner.QAPowerForWeight(actor.sectorSize, expiration-precommitEpoch, big.Zero(), big.Zero()) + oneSectorPowerEstimate := miner.QAPowerMax(actor.sectorSize) expectedDeposit := miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, big.Mul(big.NewInt(4), oneSectorPowerEstimate)) balance = big.Add(balance, expectedDeposit) rt.SetBalance(balance) diff --git a/actors/builtin/miner/monies.go b/actors/builtin/miner/monies.go index 8a2d58c76..0db2c0e03 100644 --- a/actors/builtin/miner/monies.go +++ b/actors/builtin/miner/monies.go @@ -4,7 +4,6 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/exitcode" - rtt "github.com/filecoin-project/go-state-types/rt" "github.com/filecoin-project/specs-actors/v7/actors/builtin" "github.com/filecoin-project/specs-actors/v7/actors/util/math" @@ -192,7 +191,6 @@ func RepayDebtsOrAbort(rt Runtime, st *State) abi.TokenAmount { currBalance := rt.CurrentBalance() toBurn, err := st.repayDebts(currBalance) builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "unlocked balance can not repay fee debt") - rt.Log(rtt.DEBUG, "RepayDebtsOrAbort was called and succeeded") return toBurn } diff --git a/actors/builtin/miner/policy.go b/actors/builtin/miner/policy.go index e3759d30e..26fc0e54d 100644 --- a/actors/builtin/miner/policy.go +++ b/actors/builtin/miner/policy.go @@ -249,6 +249,13 @@ func QualityForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, return big.Div(big.Div(scaledUpWeightedSumSpaceTime, sectorSpaceTime), builtin.QualityBaseMultiplier) } +func QAPowerMax(size abi.SectorSize) abi.StoragePower { + // return (size * VerifiedDealWeightMultiplier) / QualityBaseMultiplier + // order of operation to preserve maximum precision + // for efficiency we could change definition of VerifiedDealWeightMultiplier to be more efficient + return big.Div(big.Mul(big.NewIntUnsigned(uint64(size)), builtin.VerifiedDealWeightMultiplier), builtin.QualityBaseMultiplier) +} + // The power for a sector size, committed duration, and weight. func QAPowerForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, verifiedWeight abi.DealWeight) abi.StoragePower { quality := QualityForWeight(size, duration, dealWeight, verifiedWeight) diff --git a/actors/test/commit_post_test.go b/actors/test/commit_post_test.go index 90e1185db..1917a8a6f 100644 --- a/actors/test/commit_post_test.go +++ b/actors/test/commit_post_test.go @@ -282,7 +282,7 @@ func TestMeasurePreCommitGas(t *testing.T) { require.NoError(t, err) addrs := vm.CreateAccounts(ctx, t, v, 1, big.Mul(big.NewInt(100_000), builtin.TokenPrecision), 93837778) owner, worker := addrs[0], addrs[0] - minerAddrs := createMiner(t, v, owner, worker, wPoStProof, big.Mul(big.NewInt(10_000), vm.FIL)) + minerAddrs := createMiner(t, v, owner, worker, wPoStProof, big.Mul(big.NewInt(100_000), vm.FIL)) // Advance vm so we can have seal randomness epoch in the past v, err = v.WithEpoch(abi.ChainEpoch(200)) @@ -327,9 +327,9 @@ func TestMeasurePoRepGas(t *testing.T) { wPoStProof, err := sealProof.RegisteredWindowPoStProof() require.NoError(t, err) - addrs := vm.CreateAccounts(ctx, t, v, 1, big.Mul(big.NewInt(10_000), builtin.TokenPrecision), 93837778) + addrs := vm.CreateAccounts(ctx, t, v, 1, big.Mul(big.NewInt(100_000), builtin.TokenPrecision), 93837778) owner, worker := addrs[0], addrs[0] - minerAddrs := createMiner(t, v, owner, worker, wPoStProof, big.Mul(big.NewInt(10_000), vm.FIL)) + minerAddrs := createMiner(t, v, owner, worker, wPoStProof, big.Mul(big.NewInt(100_000), vm.FIL)) // advance vm so we can have seal randomness epoch in the past v, err = v.WithEpoch(abi.ChainEpoch(200)) @@ -620,14 +620,14 @@ func TestAggregateSizeLimits(t *testing.T) { ctx := context.Background() blkStore := ipld.NewBlockStoreInMemory() v := vm.NewVMWithSingletons(ctx, t, blkStore) - addrs := vm.CreateAccounts(ctx, t, v, 1, big.Mul(big.NewInt(10_000), big.NewInt(1e18)), 93837778) + addrs := vm.CreateAccounts(ctx, t, v, 1, big.Mul(big.NewInt(100_000), big.NewInt(1e18)), 93837778) // create miner sealProof := abi.RegisteredSealProof_StackedDrg32GiBV1_1 wPoStProof, err := sealProof.RegisteredWindowPoStProof() require.NoError(t, err) owner, worker := addrs[0], addrs[0] - minerAddrs := createMiner(t, v, owner, worker, wPoStProof, big.Mul(big.NewInt(10_000), vm.FIL)) + minerAddrs := createMiner(t, v, owner, worker, wPoStProof, big.Mul(big.NewInt(100_000), vm.FIL)) // advance vm so we can have seal randomness epoch in the past v, err = v.WithEpoch(abi.ChainEpoch(200)) @@ -780,9 +780,9 @@ func TestMeasureAggregatePorepGas(t *testing.T) { sealProof := abi.RegisteredSealProof_StackedDrg32GiBV1_1 wPoStProof, err := sealProof.RegisteredWindowPoStProof() require.NoError(t, err) - addrs := vm.CreateAccounts(ctx, t, v, 1, big.Mul(big.NewInt(10_000), builtin.TokenPrecision), 93837778) + addrs := vm.CreateAccounts(ctx, t, v, 1, big.Mul(big.NewInt(100_000), builtin.TokenPrecision), 93837778) owner, worker := addrs[0], addrs[0] - minerAddrs := createMiner(t, v, owner, worker, wPoStProof, big.Mul(big.NewInt(10_000), vm.FIL)) + minerAddrs := createMiner(t, v, owner, worker, wPoStProof, big.Mul(big.NewInt(100_000), vm.FIL)) // advance vm so we can have seal randomness epoch in the past v, err = v.WithEpoch(abi.ChainEpoch(200)) diff --git a/support/agent/cases_test.go b/support/agent/cases_test.go index 39d114980..05630ca36 100644 --- a/support/agent/cases_test.go +++ b/support/agent/cases_test.go @@ -23,7 +23,7 @@ import ( func TestCreate20Miners(t *testing.T) { ctx := context.Background() - initialBalance := big.Mul(big.NewInt(1000), big.NewInt(1e18)) + initialBalance := big.Mul(big.NewInt(10000), big.NewInt(1e18)) minerCount := 20 rnd := rand.New(rand.NewSource(42)) From 0ef499a04bc3075270a3a64d64727af30835a681 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera <kubuxu@protocol.ai> Date: Tue, 8 Mar 2022 15:14:03 +0100 Subject: [PATCH 2/4] Prototype deal verification at ProveCommit and Activation Batching Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai> --- actors/builtin/market/cbor_gen.go | 383 ++++++++++++++++++++++++++ actors/builtin/market/market_actor.go | 124 ++++++--- actors/builtin/miner/cbor_gen.go | 124 ++------- actors/builtin/miner/miner_actor.go | 202 ++++++++++---- actors/builtin/miner/miner_state.go | 33 +-- gen/gen.go | 11 +- 6 files changed, 672 insertions(+), 205 deletions(-) diff --git a/actors/builtin/market/cbor_gen.go b/actors/builtin/market/cbor_gen.go index 4ed5bd11c..a459c7830 100644 --- a/actors/builtin/market/cbor_gen.go +++ b/actors/builtin/market/cbor_gen.go @@ -398,3 +398,386 @@ func (t *DealState) UnmarshalCBOR(r io.Reader) error { } return nil } + +var lengthBufActivateDealsParams = []byte{129} + +func (t *ActivateDealsParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufActivateDealsParams); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Sectors ([]market.ActivateDealsParamsInner) (slice) + if len(t.Sectors) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Sectors was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Sectors))); err != nil { + return err + } + for _, v := range t.Sectors { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *ActivateDealsParams) UnmarshalCBOR(r io.Reader) error { + *t = ActivateDealsParams{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Sectors ([]market.ActivateDealsParamsInner) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Sectors: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Sectors = make([]ActivateDealsParamsInner, extra) + } + + for i := 0; i < int(extra); i++ { + + var v ActivateDealsParamsInner + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Sectors[i] = v + } + + return nil +} + +var lengthBufActivateDealsParamsInner = []byte{130} + +func (t *ActivateDealsParamsInner) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufActivateDealsParamsInner); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.DealIDs ([]abi.DealID) (slice) + if len(t.DealIDs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.DealIDs was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.DealIDs))); err != nil { + return err + } + for _, v := range t.DealIDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } + } + + // t.SectorExpiry (abi.ChainEpoch) (int64) + if t.SectorExpiry >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.SectorExpiry)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.SectorExpiry-1)); err != nil { + return err + } + } + return nil +} + +func (t *ActivateDealsParamsInner) UnmarshalCBOR(r io.Reader) error { + *t = ActivateDealsParamsInner{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.DealIDs ([]abi.DealID) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.DealIDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.DealIDs = make([]abi.DealID, extra) + } + + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj) + } + + t.DealIDs[i] = abi.DealID(val) + } + + // t.SectorExpiry (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SectorExpiry = abi.ChainEpoch(extraI) + } + return nil +} + +var lengthBufActivateDealsReturn = []byte{129} + +func (t *ActivateDealsReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufActivateDealsReturn); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Sectors ([]market.ActivateDealsReturnInner) (slice) + if len(t.Sectors) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Sectors was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Sectors))); err != nil { + return err + } + for _, v := range t.Sectors { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *ActivateDealsReturn) UnmarshalCBOR(r io.Reader) error { + *t = ActivateDealsReturn{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Sectors ([]market.ActivateDealsReturnInner) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Sectors: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Sectors = make([]ActivateDealsReturnInner, extra) + } + + for i := 0; i < int(extra); i++ { + + var v ActivateDealsReturnInner + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Sectors[i] = v + } + + return nil +} + +var lengthBufActivateDealsReturnInner = []byte{132} + +func (t *ActivateDealsReturnInner) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufActivateDealsReturnInner); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Success (bool) (bool) + if err := cbg.WriteBool(w, t.Success); err != nil { + return err + } + + // t.DealSpace (uint64) (uint64) + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.DealSpace)); err != nil { + return err + } + + // t.DealWeight (big.Int) (struct) + if err := t.DealWeight.MarshalCBOR(w); err != nil { + return err + } + + // t.VerifiedDealWeight (big.Int) (struct) + if err := t.VerifiedDealWeight.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *ActivateDealsReturnInner) UnmarshalCBOR(r io.Reader) error { + *t = ActivateDealsReturnInner{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Success (bool) (bool) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Success = false + case 21: + t.Success = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.DealSpace (uint64) (uint64) + + { + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.DealSpace = uint64(extra) + + } + // t.DealWeight (big.Int) (struct) + + { + + if err := t.DealWeight.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.DealWeight: %w", err) + } + + } + // t.VerifiedDealWeight (big.Int) (struct) + + { + + if err := t.VerifiedDealWeight.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.VerifiedDealWeight: %w", err) + } + + } + return nil +} diff --git a/actors/builtin/market/market_actor.go b/actors/builtin/market/market_actor.go index 116277297..edd9015cd 100644 --- a/actors/builtin/market/market_actor.go +++ b/actors/builtin/market/market_actor.go @@ -406,15 +406,32 @@ func (a Actor) VerifyDealsForActivation(rt Runtime, params *VerifyDealsForActiva } } -//type ActivateDealsParams struct { -// DealIDs []abi.DealID -// SectorExpiry abi.ChainEpoch -//} -type ActivateDealsParams = market0.ActivateDealsParams +type ActivateDealsParams struct { + Sectors []ActivateDealsParamsInner +} + +//cbor-gen is annoying +type ActivateDealsParamsInner struct { + DealIDs []abi.DealID + SectorExpiry abi.ChainEpoch +} + +type ActivateDealsReturn struct { + Sectors []ActivateDealsReturnInner +} + +type ActivateDealsReturnInner struct { + Success bool // True if activation was a success + DealSpace uint64 // Total space in bytes of submitted deals. + DealWeight abi.DealWeight // Total space*time of submitted deals. + VerifiedDealWeight abi.DealWeight // Total space*time of submitted verified deals. +} // Verify that a given set of storage deals is valid for a sector currently being ProveCommitted, // update the market's internal state accordingly. -func (a Actor) ActivateDeals(rt Runtime, params *ActivateDealsParams) *abi.EmptyValue { +// TODO: ActivateDeals somehow needs to check DealSpace <= SectorSize +// currently it was done at precommit +func (a Actor) ActivateDeals(rt Runtime, params *ActivateDealsParams) *ActivateDealsReturn { rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) minerAddr := rt.Caller() currEpoch := rt.CurrEpoch() @@ -422,50 +439,83 @@ func (a Actor) ActivateDeals(rt Runtime, params *ActivateDealsParams) *abi.Empty var st State store := adt.AsStore(rt) + res := make([]ActivateDealsReturnInner, len(params.Sectors)) + // Update deal dealStates. rt.StateTransaction(&st, func() { - _, _, _, err := ValidateDealsForActivation(&st, store, params.DealIDs, minerAddr, params.SectorExpiry, currEpoch) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to validate dealProposals for activation") - - msm, err := st.mutator(adt.AsStore(rt)).withDealStates(WritePermission). - withPendingProposals(ReadOnlyPermission).withDealProposals(ReadOnlyPermission).build() - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load state") - for _, dealID := range params.DealIDs { - // This construction could be replaced with a single "update deal state" state method, possibly batched - // over all deal ids at once. - _, found, err := msm.dealStates.Get(dealID) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to get state for dealId %d", dealID) - if found { - rt.Abortf(exitcode.ErrIllegalArgument, "deal %d already included in another sector", dealID) + outer: + for i, sector := range params.Sectors { + dealWeight, verifiedWeight, dealSpace, err := ValidateDealsForActivation(&st, store, sector.DealIDs, minerAddr, sector.SectorExpiry, currEpoch) + //builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to validate dealProposals for activation") + if err != nil { + continue outer } - proposal, err := getDealProposal(msm.dealProposals, dealID) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to get dealId %d", dealID) + msm, err := st.mutator(adt.AsStore(rt)).withDealStates(WritePermission). + withPendingProposals(ReadOnlyPermission).withDealProposals(ReadOnlyPermission).build() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load state") + + for _, dealID := range sector.DealIDs { + // This construction could be replaced with a single "update deal state" state method, possibly batched + // over all deal ids at once. + _, found, err := msm.dealStates.Get(dealID) + //builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to get state for dealId %d", dealID) + if err != nil { + continue outer + } - propc, err := proposal.Cid() - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to calculate proposal CID") + if found { + //rt.Abortf(exitcode.ErrIllegalArgument, "deal %d already included in another sector", dealID) + if err != nil { + continue outer + } + } + + proposal, err := getDealProposal(msm.dealProposals, dealID) + //builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to get dealId %d", dealID) + if err != nil { + continue outer + } + + propc, err := proposal.Cid() + //builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to calculate proposal CID") + if err != nil { + continue outer + } + + has, err := msm.pendingDeals.Has(abi.CidKey(propc)) + //builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to get pending proposal %v", propc) + if err != nil { + continue outer + } - has, err := msm.pendingDeals.Has(abi.CidKey(propc)) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to get pending proposal %v", propc) + if !has { + // rt.Abortf(exitcode.ErrIllegalState, "tried to activate deal that was not in the pending set (%s)", propc) + continue outer + } - if !has { - rt.Abortf(exitcode.ErrIllegalState, "tried to activate deal that was not in the pending set (%s)", propc) + err = msm.dealStates.Set(dealID, &DealState{ + SectorStartEpoch: currEpoch, + LastUpdatedEpoch: epochUndefined, + SlashEpoch: epochUndefined, + }) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to set deal state %d", dealID) } - err = msm.dealStates.Set(dealID, &DealState{ - SectorStartEpoch: currEpoch, - LastUpdatedEpoch: epochUndefined, - SlashEpoch: epochUndefined, - }) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to set deal state %d", dealID) - } + res[i] = ActivateDealsReturnInner{ + Success: true, + DealSpace: dealSpace, + DealWeight: dealWeight, + VerifiedDealWeight: verifiedWeight, + } - err = msm.commitState() - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush state") + err = msm.commitState() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush state") + } }) - return nil + return &ActivateDealsReturn{Sectors: res} } //type SectorDataSpec struct { diff --git a/actors/builtin/miner/cbor_gen.go b/actors/builtin/miner/cbor_gen.go index b2972b9f1..5d4fc3fb4 100644 --- a/actors/builtin/miner/cbor_gen.go +++ b/actors/builtin/miner/cbor_gen.go @@ -1367,7 +1367,7 @@ func (t *PowerPair) UnmarshalCBOR(r io.Reader) error { return nil } -var lengthBufSectorPreCommitOnChainInfo = []byte{133} +var lengthBufSectorPreCommitOnChainInfo = []byte{131} func (t *SectorPreCommitOnChainInfo) MarshalCBOR(w io.Writer) error { if t == nil { @@ -1400,16 +1400,6 @@ func (t *SectorPreCommitOnChainInfo) MarshalCBOR(w io.Writer) error { return err } } - - // t.DealWeight (big.Int) (struct) - if err := t.DealWeight.MarshalCBOR(w); err != nil { - return err - } - - // t.VerifiedDealWeight (big.Int) (struct) - if err := t.VerifiedDealWeight.MarshalCBOR(w); err != nil { - return err - } return nil } @@ -1427,7 +1417,7 @@ func (t *SectorPreCommitOnChainInfo) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input should be of type array") } - if extra != 5 { + if extra != 3 { return fmt.Errorf("cbor input had wrong number of fields") } @@ -1474,28 +1464,10 @@ func (t *SectorPreCommitOnChainInfo) UnmarshalCBOR(r io.Reader) error { t.PreCommitEpoch = abi.ChainEpoch(extraI) } - // t.DealWeight (big.Int) (struct) - - { - - if err := t.DealWeight.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.DealWeight: %w", err) - } - - } - // t.VerifiedDealWeight (big.Int) (struct) - - { - - if err := t.VerifiedDealWeight.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.VerifiedDealWeight: %w", err) - } - - } return nil } -var lengthBufSectorPreCommitInfo = []byte{138} +var lengthBufSectorPreCommitInfo = []byte{135} func (t *SectorPreCommitInfo) MarshalCBOR(w io.Writer) error { if t == nil { @@ -1567,27 +1539,16 @@ func (t *SectorPreCommitInfo) MarshalCBOR(w io.Writer) error { } } - // t.ReplaceCapacity (bool) (bool) - if err := cbg.WriteBool(w, t.ReplaceCapacity); err != nil { - return err - } - - // t.ReplaceSectorDeadline (uint64) (uint64) - - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.ReplaceSectorDeadline)); err != nil { - return err - } - - // t.ReplaceSectorPartition (uint64) (uint64) + // t.UnsealedCID (cid.Cid) (struct) - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.ReplaceSectorPartition)); err != nil { - return err - } - - // t.ReplaceSectorNumber (abi.SectorNumber) (uint64) - - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.ReplaceSectorNumber)); err != nil { - return err + if t.UnsealedCID == nil { + if _, err := w.Write(cbg.CborNull); err != nil { + return err + } + } else { + if err := cbg.WriteCidBuf(scratch, w, *t.UnsealedCID); err != nil { + return xerrors.Errorf("failed to write cid field t.UnsealedCID: %w", err) + } } return nil @@ -1607,7 +1568,7 @@ func (t *SectorPreCommitInfo) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input should be of type array") } - if extra != 10 { + if extra != 7 { return fmt.Errorf("cbor input had wrong number of fields") } @@ -1745,63 +1706,26 @@ func (t *SectorPreCommitInfo) UnmarshalCBOR(r io.Reader) error { t.Expiration = abi.ChainEpoch(extraI) } - // t.ReplaceCapacity (bool) (bool) - - maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - if maj != cbg.MajOther { - return fmt.Errorf("booleans must be major type 7") - } - switch extra { - case 20: - t.ReplaceCapacity = false - case 21: - t.ReplaceCapacity = true - default: - return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) - } - // t.ReplaceSectorDeadline (uint64) (uint64) + // t.UnsealedCID (cid.Cid) (struct) { - maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - if maj != cbg.MajUnsignedInt { - return fmt.Errorf("wrong type for uint64 field") - } - t.ReplaceSectorDeadline = uint64(extra) - - } - // t.ReplaceSectorPartition (uint64) (uint64) - - { - - maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + b, err := br.ReadByte() if err != nil { return err } - if maj != cbg.MajUnsignedInt { - return fmt.Errorf("wrong type for uint64 field") - } - t.ReplaceSectorPartition = uint64(extra) - - } - // t.ReplaceSectorNumber (abi.SectorNumber) (uint64) + if b != cbg.CborNull[0] { + if err := br.UnreadByte(); err != nil { + return err + } - { + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.UnsealedCID: %w", err) + } - maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - if maj != cbg.MajUnsignedInt { - return fmt.Errorf("wrong type for uint64 field") + t.UnsealedCID = &c } - t.ReplaceSectorNumber = abi.SectorNumber(extra) } return nil diff --git a/actors/builtin/miner/miner_actor.go b/actors/builtin/miner/miner_actor.go index f63269f45..8c6c27934 100644 --- a/actors/builtin/miner/miner_actor.go +++ b/actors/builtin/miner/miner_actor.go @@ -78,6 +78,7 @@ func (a Actor) Exports() []interface{} { 25: a.PreCommitSectorBatch, 26: a.ProveCommitAggregate, 27: a.ProveReplicaUpdates, + 28: a.PreCommitSectorBatch2, } } @@ -676,6 +677,40 @@ type PreCommitSectorBatchParams = miner5.PreCommitSectorBatchParams // This method calculates the sector's power, locks a pre-commit deposit for the sector, stores information about the // sector in state and waits for it to be proven or expire. func (a Actor) PreCommitSectorBatch(rt Runtime, params *PreCommitSectorBatchParams) *abi.EmptyValue { + newSectors := make([]SectorPreCommitInfo, 0, len(params.Sectors)) + for _, pi := range params.Sectors { + if pi.ReplaceCapacity { + rt.Abortf(exitcode.SysErrForbidden, "cc upgrade through precommit discontinued, use lightweight cc upgrade instead") + } + newSectors = append(newSectors, SectorPreCommitInfo{ + SealProof: pi.SealProof, + SectorNumber: pi.SectorNumber, + SealedCID: pi.SealedCID, + SealRandEpoch: pi.SealRandEpoch, + DealIDs: pi.DealIDs, + Expiration: pi.Expiration, + UnsealedCID: nil, + }) + } + + return a.preCommitSectorBatch2Inner(rt, &PreCommitSectorBatch2Params{Sectors: newSectors}, false) +} + +type PreCommitSectorBatch2Params struct { + Sectors []SectorPreCommitInfo +} + +// Pledges the miner to seal and commit some new sectors. +// The caller specifies sector numbers, sealed sector data CIDs, seal randomness epoch, expiration, UnsealedCID, and the IDs +// of any storage deals contained in the sector data. The storage deal proposals should be already submitted +// to the storage market actor. +// This method assumes maximum sector power, locks a pre-commit deposit for the sector, stores information about the +// sector in state and waits for it to be proven or expire. +func (a Actor) PreCommitSectorBatch2(rt Runtime, params *PreCommitSectorBatch2Params) *abi.EmptyValue { + return a.preCommitSectorBatch2Inner(rt, params, true) +} + +func (a Actor) preCommitSectorBatch2Inner(rt Runtime, params *PreCommitSectorBatch2Params, newBehaviour bool) *abi.EmptyValue { currEpoch := rt.CurrEpoch() if len(params.Sectors) == 0 { rt.Abortf(exitcode.ErrIllegalArgument, "batch empty") @@ -714,16 +749,27 @@ func (a Actor) PreCommitSectorBatch(rt Runtime, params *PreCommitSectorBatchPara if precommit.SealRandEpoch < challengeEarliest { rt.Abortf(exitcode.ErrIllegalArgument, "seal challenge epoch %v too old, must be after %v", precommit.SealRandEpoch, challengeEarliest) } + if precommit.UnsealedCID != nil { + if !precommit.UnsealedCID.Defined() { + rt.Abortf(exitcode.ErrIllegalArgument, "unsealed CID undefined") + } + if precommit.UnsealedCID.Prefix() != market.PieceCIDPrefix { + rt.Abortf(exitcode.ErrIllegalArgument, "unsealed CID had wrong prefix") + } + if len(precommit.DealIDs) == 0 { + rt.Abortf(exitcode.ErrIllegalArgument, "UnsealedCID passed when there are no deals") + } + } else { + if newBehaviour && (len(precommit.DealIDs) > 0) { + rt.Abortf(exitcode.ErrIllegalArgument, "UnsealedCID missing when there are deals") + } + } // Require sector lifetime meets minimum by assuming activation happens at last epoch permitted for seal proof. // This could make sector maximum lifetime validation more lenient if the maximum sector limit isn't hit first. maxActivation := currEpoch + MaxProveCommitDuration[precommit.SealProof] validateExpiration(rt, maxActivation, precommit.Expiration, precommit.SealProof) - if precommit.ReplaceCapacity { - rt.Abortf(exitcode.SysErrForbidden, "cc upgrade through precommit discontinued, use lightweight cc upgrade instead") - } - sectorsDeals[i] = market.SectorDeals{ SectorExpiry: precommit.Expiration, DealIDs: precommit.DealIDs, @@ -733,11 +779,9 @@ func (a Actor) PreCommitSectorBatch(rt Runtime, params *PreCommitSectorBatchPara // gather information from other actors rewardStats := requestCurrentEpochBlockReward(rt) pwrTotal := requestCurrentTotalPower(rt) - dealWeights := requestDealWeights(rt, sectorsDeals) - if len(dealWeights.Sectors) != len(params.Sectors) { - rt.Abortf(exitcode.ErrIllegalState, "deal weight request returned %d records, expected %d", - len(dealWeights.Sectors), len(params.Sectors)) + if !newBehaviour { + verifyDealsForActivation(rt, sectorsDeals) } store := adt.AsStore(rt) @@ -785,23 +829,15 @@ func (a Actor) PreCommitSectorBatch(rt Runtime, params *PreCommitSectorBatchPara rt.Abortf(exitcode.ErrIllegalArgument, "too many deals for sector %d > %d", len(precommit.DealIDs), dealCountMax) } - // Ensure total deal space does not exceed sector size. - dealWeight := dealWeights.Sectors[i] - if dealWeight.DealSpace > uint64(info.SectorSize) { - rt.Abortf(exitcode.ErrIllegalArgument, "deals too large to fit in sector %d > %d", dealWeight.DealSpace, info.SectorSize) - } - // For PreCommitDeposit we estimate maximum possible power of the sector sectorWeight := QAPowerMax(info.SectorSize) depositReq := PreCommitDepositForPower(rewardStats.ThisEpochRewardSmoothed, pwrTotal.QualityAdjPowerSmoothed, sectorWeight) // Build on-chain record. chainInfos[i] = &SectorPreCommitOnChainInfo{ - Info: SectorPreCommitInfo(precommit), - PreCommitDeposit: depositReq, - PreCommitEpoch: currEpoch, - DealWeight: dealWeight.DealWeight, - VerifiedDealWeight: dealWeight.VerifiedDealWeight, + Info: SectorPreCommitInfo(precommit), + PreCommitDeposit: depositReq, + PreCommitEpoch: currEpoch, } totalDepositRequired = big.Add(totalDepositRequired, depositReq) @@ -913,6 +949,18 @@ func (a Actor) ProveCommitAggregate(rt Runtime, params *ProveCommitAggregatePara // compute shared verification inputs commDs := requestUnsealedSectorCIDs(rt, computeDataCommitmentsInputs...) + for i, precommit := range precommits { + if len(precommit.Info.DealIDs) > 0 { + if precommit.Info.UnsealedCID != nil { + // new precommit + if !precommit.Info.UnsealedCID.Equals(commDs[i]) { + rt.Abortf(exitcode.ErrIllegalState, "miscomputed UnsealedCID") + } + } else { + // old precommit, no check needed, checked at precommit + } + } + } svis := make([]proof.AggregateSealVerifyInfo, 0) receiver := rt.Receiver() minerActorID, err := addr.IDFromAddress(receiver) @@ -1029,6 +1077,7 @@ func (a Actor) ProveCommitSector(rt Runtime, params *ProveCommitSectorParams) *a DealIDs: precommit.Info.DealIDs, SectorNumber: precommit.Info.SectorNumber, RegisteredSealProof: precommit.Info.SealProof, + UnsealedCID: precommit.Info.UnsealedCID, }) code := rt.Send( @@ -1082,30 +1131,41 @@ func confirmSectorProofsValid(rt Runtime, preCommits []*SectorPreCommitOnChainIn activation := rt.CurrEpoch() // Pre-commits for new sectors. + + var sectorsToActivate []market.ActivateDealsParamsInner + var preCommitsToActivate []*SectorPreCommitOnChainInfo + var validPreCommits []*SectorPreCommitOnChainInfo for _, precommit := range preCommits { if len(precommit.Info.DealIDs) > 0 { - // Check (and activate) storage deals associated to sector. Abort if checks failed. - // TODO: we should batch these calls... - // https://github.com/filecoin-project/specs-actors/issues/474 - code := rt.Send( - builtin.StorageMarketActorAddr, - builtin.MethodsMarket.ActivateDeals, - &market.ActivateDealsParams{ - DealIDs: precommit.Info.DealIDs, - SectorExpiry: precommit.Info.Expiration, - }, - abi.NewTokenAmount(0), - &builtin.Discard{}, - ) - - if code != exitcode.Ok { - rt.Log(rtt.INFO, "failed to activate deals on sector %d, dropping from prove commit set", precommit.Info.SectorNumber) - continue - } + sectorsToActivate = append(sectorsToActivate, market.ActivateDealsParamsInner{ + DealIDs: precommit.Info.DealIDs, + SectorExpiry: precommit.Info.Expiration, + }) + preCommitsToActivate = append(preCommitsToActivate, precommit) + } else { + validPreCommits = append(validPreCommits, precommit) } + } + var activateRes market.ActivateDealsReturn + code := rt.Send( + builtin.StorageMarketActorAddr, + builtin.MethodsMarket.ActivateDeals, + &market.ActivateDealsParams{ + Sectors: sectorsToActivate, + }, + abi.NewTokenAmount(0), + &activateRes, + ) + builtin.RequireSuccess(rt, code, "failed batch deal activation") - validPreCommits = append(validPreCommits, precommit) + sectorWeights := make(map[abi.SectorNumber]market.ActivateDealsReturnInner) + for i, weight := range activateRes.Sectors { + if !weight.Success { + continue + } + sectorWeights[preCommitsToActivate[i].Info.SectorNumber] = weight + validPreCommits = append(validPreCommits, preCommitsToActivate[i]) } // When all prove commits have failed abort early @@ -1131,7 +1191,15 @@ func confirmSectorProofsValid(rt Runtime, preCommits []*SectorPreCommitOnChainIn rt.Log(rtt.WARN, "precommit %d has lifetime %d less than minimum. ignoring", precommit.Info.SectorNumber, duration, MinSectorExpiration) continue } - pwr := QAPowerForWeight(info.SectorSize, duration, precommit.DealWeight, precommit.VerifiedDealWeight) + + dealWeight := big.Zero() + verifiedDealWeight := big.Zero() + if weight, ok := sectorWeights[precommit.Info.SectorNumber]; ok { + dealWeight = weight.DealWeight + verifiedDealWeight = weight.VerifiedDealWeight + } + + pwr := QAPowerForWeight(info.SectorSize, duration, dealWeight, verifiedDealWeight) dayReward := ExpectedRewardForPower(thisEpochRewardSmoothed, qualityAdjPowerSmoothed, pwr, builtin.EpochsInDay) // The storage pledge is recorded for use in computing the penalty if this sector is terminated @@ -1148,8 +1216,8 @@ func confirmSectorProofsValid(rt Runtime, preCommits []*SectorPreCommitOnChainIn DealIDs: precommit.Info.DealIDs, Expiration: precommit.Info.Expiration, Activation: activation, - DealWeight: precommit.DealWeight, - VerifiedDealWeight: precommit.VerifiedDealWeight, + DealWeight: dealWeight, + VerifiedDealWeight: verifiedDealWeight, InitialPledge: initialPledge, ExpectedDayReward: dayReward, ExpectedStoragePledge: storagePledge, @@ -2166,18 +2234,21 @@ func (a Actor) ProveReplicaUpdates(rt Runtime, params *ProveReplicaUpdatesParams continue } + var activateRes market.ActivateDealsReturn code := rt.Send( builtin.StorageMarketActorAddr, builtin.MethodsMarket.ActivateDeals, &market.ActivateDealsParams{ - DealIDs: update.Deals, - SectorExpiry: sectorInfo.Expiration, + Sectors: []market.ActivateDealsParamsInner{{ + DealIDs: update.Deals, + SectorExpiry: sectorInfo.Expiration, + }}, }, abi.NewTokenAmount(0), - &builtin.Discard{}, + &activateRes, ) - if code != exitcode.Ok { + if code != exitcode.Ok || !activateRes.Sectors[0].Success { rt.Log(rtt.INFO, "failed to activate deals, skipping sector %d", update.SectorID) continue } @@ -2748,6 +2819,7 @@ type SealVerifyStuff struct { DealIDs []abi.DealID abi.SectorNumber SealRandEpoch abi.ChainEpoch // Used to tie the seal to a chain. + UnsealedCID *cid.Cid } func getVerifyInfo(rt Runtime, params *SealVerifyStuff) *proof.SealVerifyInfo { @@ -2755,10 +2827,21 @@ func getVerifyInfo(rt Runtime, params *SealVerifyStuff) *proof.SealVerifyInfo { rt.Abortf(exitcode.ErrForbidden, "too early to prove sector") } - commDs := requestUnsealedSectorCIDs(rt, &market.SectorDataSpec{ + commD := requestUnsealedSectorCIDs(rt, &market.SectorDataSpec{ SectorType: params.RegisteredSealProof, DealIDs: params.DealIDs, - }) + })[0] + + if len(params.DealIDs) > 0 { + if params.UnsealedCID != nil { + // new precommit + if !params.UnsealedCID.Equals(commD) { + rt.Abortf(exitcode.ErrIllegalState, "miscomputed UnsealedCID") + } + } else { + // old precommit, no check needed, checked at precommit + } + } minerActorID, err := addr.IDFromAddress(rt.Receiver()) builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "runtime provided non-ID receiver address %v", rt.Receiver()) @@ -2782,7 +2865,7 @@ func getVerifyInfo(rt Runtime, params *SealVerifyStuff) *proof.SealVerifyInfo { Proof: params.Proof, Randomness: abi.SealRandomness(svInfoRandomness), SealedCID: params.SealedCID, - UnsealedCID: commDs[0], + UnsealedCID: commD, } } @@ -2810,6 +2893,25 @@ func requestUnsealedSectorCIDs(rt Runtime, dataCommitmentInputs ...*market.Secto return unsealedCIDs } +func verifyDealsForActivation(rt Runtime, sectors []market.SectorDeals) { + var dealWeights market.VerifyDealsForActivationReturn + code := rt.Send( + builtin.StorageMarketActorAddr, + builtin.MethodsMarket.VerifyDealsForActivation, + &market.VerifyDealsForActivationParams{ + Sectors: sectors, + }, + abi.NewTokenAmount(0), + &dealWeights, + ) + builtin.RequireSuccess(rt, code, "failed to verify deals and get deal weight") + if len(dealWeights.Sectors) != len(sectors) { + rt.Abortf(exitcode.ErrIllegalState, "deal weight request returned %d records, expected %d", + len(dealWeights.Sectors), len(sectors)) + } +} + +// TODO remove?? func requestDealWeights(rt Runtime, sectors []market.SectorDeals) *market.VerifyDealsForActivationReturn { // Short-circuit if there are no deals in any of the sectors. dealCount := 0 @@ -2841,6 +2943,10 @@ func requestDealWeights(rt Runtime, sectors []market.SectorDeals) *market.Verify &dealWeights, ) builtin.RequireSuccess(rt, code, "failed to verify deals and get deal weight") + if len(dealWeights.Sectors) != len(sectors) { + rt.Abortf(exitcode.ErrIllegalState, "deal weight request returned %d records, expected %d", + len(dealWeights.Sectors), len(sectors)) + } return &dealWeights } diff --git a/actors/builtin/miner/miner_state.go b/actors/builtin/miner/miner_state.go index ff20ef3d9..652d2e91f 100644 --- a/actors/builtin/miner/miner_state.go +++ b/actors/builtin/miner/miner_state.go @@ -133,28 +133,29 @@ type WorkerKeyChange struct { EffectiveAt abi.ChainEpoch } +// possible states +// (DealIDs > 0, UnsealedCID != nil) => CommD provided by SP, needs to be checked +// (DealIDs > 0, UnsealedCID == nil) => Old method or migration, DealIDs checked at PreCommit (Depracated) +// (DealIDs == 0, UnsealedCID == nil) => NoDeals, CommD of empty sector +// (DealIDs == 0, UnsealedCID != 0) future approach, fail for now // Information provided by a miner when pre-committing a sector. type SectorPreCommitInfo struct { - SealProof abi.RegisteredSealProof - SectorNumber abi.SectorNumber - SealedCID cid.Cid `checked:"true"` // CommR - SealRandEpoch abi.ChainEpoch - DealIDs []abi.DealID - Expiration abi.ChainEpoch - ReplaceCapacity bool // Whether to replace a "committed capacity" no-deal sector (requires non-empty DealIDs) - // The committed capacity sector to replace, and it's deadline/partition location - ReplaceSectorDeadline uint64 - ReplaceSectorPartition uint64 - ReplaceSectorNumber abi.SectorNumber + SealProof abi.RegisteredSealProof + SectorNumber abi.SectorNumber + SealedCID cid.Cid `checked:"true"` // CommR + SealRandEpoch abi.ChainEpoch + DealIDs []abi.DealID + Expiration abi.ChainEpoch + UnsealedCID *cid.Cid `checked:"true"` } // Information stored on-chain for a pre-committed sector. type SectorPreCommitOnChainInfo struct { - Info SectorPreCommitInfo - PreCommitDeposit abi.TokenAmount - PreCommitEpoch abi.ChainEpoch - DealWeight abi.DealWeight // Integral of active deals over sector lifetime - VerifiedDealWeight abi.DealWeight // Integral of active verified deals over sector lifetime + Info SectorPreCommitInfo + PreCommitDeposit abi.TokenAmount + PreCommitEpoch abi.ChainEpoch + //DealWeight abi.DealWeight // Integral of active deals over sector lifetime + //VerifiedDealWeight abi.DealWeight // Integral of active verified deals over sector lifetime } // Information stored on-chain for a proven sector. diff --git a/gen/gen.go b/gen/gen.go index d11535e91..472ebc715 100644 --- a/gen/gen.go +++ b/gen/gen.go @@ -119,7 +119,7 @@ func main() { // method params and returns //paych.ConstructorParams{}, // Aliased from v0 paych.UpdateChannelStateParams{}, // Changed in v7 - paych.SignedVoucher{}, // Changed in v7 + paych.SignedVoucher{}, // Changed in v7 //paych.ModVerifyParams{}, // Aliased from v0 // other types //paych.Merge{}, // Aliased from v0 @@ -152,7 +152,10 @@ func main() { //market.WithdrawBalanceParams{}, // Aliased from v0 // market.PublishStorageDealsParams{}, // Aliased from v0 //market.PublishStorageDealsReturn{}, // Aliased from v6 - //market.ActivateDealsParams{}, // Aliased from v0 + market.ActivateDealsParams{}, + market.ActivateDealsParamsInner{}, + market.ActivateDealsReturn{}, + market.ActivateDealsReturnInner{}, //market.VerifyDealsForActivationParams{}, // Aliased from v3 //market.VerifyDealsForActivationReturn{}, // Aliased from v3 //market.ComputeDataCommitmentParams{}, // Aliased from v5 @@ -230,9 +233,9 @@ func main() { verifreg.RemoveDataCapParams{}, // New in v7 verifreg.RemoveDataCapReturn{}, // New in v7 // other types - verifreg.RemoveDataCapRequest{}, // New in v7 + verifreg.RemoveDataCapRequest{}, // New in v7 verifreg.RemoveDataCapProposal{}, // New in v7 - verifreg.RmDcProposalID{}, // New in v7 + verifreg.RmDcProposalID{}, // New in v7 ); err != nil { panic(err) } From 883922a1af621d713d8ee8885fdf0032d67bf6ab Mon Sep 17 00:00:00 2001 From: Jakub Sztandera <kubuxu@protocol.ai> Date: Tue, 8 Mar 2022 23:02:03 +0100 Subject: [PATCH 3/4] Tests compile Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai> --- actors/builtin/methods.go | 3 ++- actors/builtin/miner/miner_commitment_test.go | 16 +--------------- actors/builtin/miner/miner_state_test.go | 8 +++----- actors/builtin/miner/miner_test.go | 18 ++++++++---------- 4 files changed, 14 insertions(+), 31 deletions(-) diff --git a/actors/builtin/methods.go b/actors/builtin/methods.go index bbb4f2d3f..0657f87d8 100644 --- a/actors/builtin/methods.go +++ b/actors/builtin/methods.go @@ -103,7 +103,8 @@ var MethodsMiner = struct { PreCommitSectorBatch abi.MethodNum ProveCommitAggregate abi.MethodNum ProveReplicaUpdates abi.MethodNum -}{MethodConstructor, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27} + PreCommitSectorBatch2 abi.MethodNum +}{MethodConstructor, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28} var MethodsVerifiedRegistry = struct { Constructor abi.MethodNum diff --git a/actors/builtin/miner/miner_commitment_test.go b/actors/builtin/miner/miner_commitment_test.go index 111ebfb61..a2c24ae85 100644 --- a/actors/builtin/miner/miner_commitment_test.go +++ b/actors/builtin/miner/miner_commitment_test.go @@ -91,8 +91,6 @@ func TestCommitments(t *testing.T) { // Check precommit expectations. assert.Equal(t, precommitEpoch, precommit.PreCommitEpoch) - assert.Equal(t, dealWeight, precommit.DealWeight) - assert.Equal(t, verifiedDealWeight, precommit.VerifiedDealWeight) assert.Equal(t, test.sectorNo, precommit.Info.SectorNumber) assert.Equal(t, precommitParams.SealProof, precommit.Info.SealProof) @@ -573,8 +571,6 @@ func TestPreCommitBatch(t *testing.T) { st := getState(rt) for i := 0; i < batchSize; i++ { assert.Equal(t, precommitEpoch, precommits[i].PreCommitEpoch) - assert.Equal(t, conf.sectorWeights[i].DealWeight, precommits[i].DealWeight) - assert.Equal(t, conf.sectorWeights[i].VerifiedDealWeight, precommits[i].VerifiedDealWeight) assert.Equal(t, sectorNos[i], precommits[i].Info.SectorNumber) assert.Equal(t, sectors[i].SealProof, precommits[i].Info.SealProof) @@ -675,10 +671,6 @@ func TestProveCommit(t *testing.T) { }, true) // Check precommit - // deal weights must be set in precommit onchain info - assert.Equal(t, dealWeight, precommit.DealWeight) - assert.Equal(t, verifiedDealWeight, precommit.VerifiedDealWeight) - expectedDeposit := miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, miner.QAPowerMax(actor.sectorSize)) assert.Equal(t, expectedDeposit, precommit.PreCommitDeposit) @@ -696,8 +688,6 @@ func TestProveCommit(t *testing.T) { assert.Equal(t, precommit.Info.DealIDs, sector.DealIDs) assert.Equal(t, rt.Epoch(), sector.Activation) assert.Equal(t, precommit.Info.Expiration, sector.Expiration) - assert.Equal(t, precommit.DealWeight, sector.DealWeight) - assert.Equal(t, precommit.VerifiedDealWeight, sector.VerifiedDealWeight) // expect precommit to have been removed st = getState(rt) @@ -710,14 +700,10 @@ func TestProveCommit(t *testing.T) { // The sector is exactly full with verified deals, so expect fully verified power. expectedPower := big.Mul(big.NewInt(int64(actor.sectorSize)), big.Div(builtin.VerifiedDealWeightMultiplier, builtin.QualityBaseMultiplier)) - qaPower := miner.QAPowerForWeight(actor.sectorSize, precommit.Info.Expiration-rt.Epoch(), precommit.DealWeight, precommit.VerifiedDealWeight) + qaPower := miner.QAPowerForWeight(actor.sectorSize, precommit.Info.Expiration-rt.Epoch(), sector.DealWeight, sector.VerifiedDealWeight) assert.Equal(t, expectedPower, qaPower) sectorPower := miner.NewPowerPair(big.NewIntUnsigned(uint64(actor.sectorSize)), qaPower) - // expect deal weights to be transferred to on chain info - assert.Equal(t, precommit.DealWeight, sector.DealWeight) - assert.Equal(t, precommit.VerifiedDealWeight, sector.VerifiedDealWeight) - // expect initial plege of sector to be set, and be total pledge requirement expectedInitialPledge := miner.InitialPledgeForPower(qaPower, actor.baselinePower, actor.epochRewardSmooth, actor.epochQAPowerSmooth, rt.TotalFilCircSupply()) assert.Equal(t, expectedInitialPledge, sector.InitialPledge) diff --git a/actors/builtin/miner/miner_state_test.go b/actors/builtin/miner/miner_state_test.go index 2407e3f1e..8bdedff88 100644 --- a/actors/builtin/miner/miner_state_test.go +++ b/actors/builtin/miner/miner_state_test.go @@ -1008,11 +1008,9 @@ func constructStateHarness(t *testing.T, periodBoundary abi.ChainEpoch) *stateHa func newPreCommitOnChain(sectorNo abi.SectorNumber, sealed cid.Cid, deposit abi.TokenAmount, epoch abi.ChainEpoch) *miner.SectorPreCommitOnChainInfo { info := newSectorPreCommitInfo(sectorNo, sealed) return &miner.SectorPreCommitOnChainInfo{ - Info: *info, - PreCommitDeposit: deposit, - PreCommitEpoch: epoch, - DealWeight: big.Zero(), - VerifiedDealWeight: big.Zero(), + Info: *info, + PreCommitDeposit: deposit, + PreCommitEpoch: epoch, } } diff --git a/actors/builtin/miner/miner_test.go b/actors/builtin/miner/miner_test.go index 6af3a4d90..c0abef82f 100644 --- a/actors/builtin/miner/miner_test.go +++ b/actors/builtin/miner/miner_test.go @@ -4166,9 +4166,10 @@ func (h *actorHarness) confirmSectorProofsValidInternal(rt *mock.Runtime, conf p validPrecommits = append(validPrecommits, precommit) if len(precommit.Info.DealIDs) > 0 { vdParams := market.ActivateDealsParams{ - DealIDs: precommit.Info.DealIDs, - SectorExpiry: precommit.Info.Expiration, - } + Sectors: []market.ActivateDealsParamsInner{{ + DealIDs: precommit.Info.DealIDs, + SectorExpiry: precommit.Info.Expiration, + }}} exit, found := conf.verifyDealsExit[precommit.Info.SectorNumber] if found { validPrecommits = validPrecommits[:len(validPrecommits)-1] // pop @@ -4187,21 +4188,18 @@ func (h *actorHarness) confirmSectorProofsValidInternal(rt *mock.Runtime, conf p expectRawPower := big.Zero() for _, precommit := range validPrecommits { precommitOnChain := h.getPreCommit(rt, precommit.Info.SectorNumber) + _ = precommitOnChain duration := precommit.Info.Expiration - rt.Epoch() if duration >= miner.MinSectorExpiration { - qaPowerDelta := miner.QAPowerForWeight(h.sectorSize, duration, precommitOnChain.DealWeight, precommitOnChain.VerifiedDealWeight) + //qaPowerDelta := miner.QAPowerForWeight(h.sectorSize, duration, precommitOnChain.DealWeight, precommitOnChain.VerifiedDealWeight) + // TODO DealWeight access during prove commit + qaPowerDelta := big.Zero() expectQAPower = big.Add(expectQAPower, qaPowerDelta) expectRawPower = big.Add(expectRawPower, big.NewIntUnsigned(uint64(h.sectorSize))) pledge := miner.InitialPledgeForPower(qaPowerDelta, h.baselinePower, h.epochRewardSmooth, h.epochQAPowerSmooth, rt.TotalFilCircSupply()) - // if cc upgrade, pledge is max of new and replaced pledges - if precommitOnChain.Info.ReplaceCapacity { - replaced := h.getSector(rt, precommitOnChain.Info.ReplaceSectorNumber) - pledge = big.Max(pledge, replaced.InitialPledge) - } - expectPledge = big.Add(expectPledge, pledge) } } From 3333670b6fa5627a8b6a7344cffc7ae8c1eed1ef Mon Sep 17 00:00:00 2001 From: Jakub Sztandera <kubuxu@protocol.ai> Date: Tue, 8 Mar 2022 23:12:05 +0100 Subject: [PATCH 4/4] wip on tests Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai> --- actors/builtin/miner/miner_actor.go | 15 ++++++++------- actors/builtin/miner/miner_commitment_test.go | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/actors/builtin/miner/miner_actor.go b/actors/builtin/miner/miner_actor.go index 8c6c27934..7e2bda02d 100644 --- a/actors/builtin/miner/miner_actor.go +++ b/actors/builtin/miner/miner_actor.go @@ -720,9 +720,9 @@ func (a Actor) preCommitSectorBatch2Inner(rt Runtime, params *PreCommitSectorBat // Check per-sector preconditions before opening state transaction or sending other messages. challengeEarliest := currEpoch - MaxPreCommitRandomnessLookback - sectorsDeals := make([]market.SectorDeals, len(params.Sectors)) + sectorsDeals := make([]market.SectorDeals, 0) sectorNumbers := bitfield.New() - for i, precommit := range params.Sectors { + for _, precommit := range params.Sectors { // Bitfied.IsSet() is fast when there are only locally-set values. set, err := sectorNumbers.IsSet(uint64(precommit.SectorNumber)) builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "error checking sector number") @@ -769,10 +769,11 @@ func (a Actor) preCommitSectorBatch2Inner(rt Runtime, params *PreCommitSectorBat // This could make sector maximum lifetime validation more lenient if the maximum sector limit isn't hit first. maxActivation := currEpoch + MaxProveCommitDuration[precommit.SealProof] validateExpiration(rt, maxActivation, precommit.Expiration, precommit.SealProof) - - sectorsDeals[i] = market.SectorDeals{ - SectorExpiry: precommit.Expiration, - DealIDs: precommit.DealIDs, + if len(precommit.DealIDs) > 0 { + sectorsDeals = append(sectorsDeals, market.SectorDeals{ + SectorExpiry: precommit.Expiration, + DealIDs: precommit.DealIDs, + }) } } @@ -780,7 +781,7 @@ func (a Actor) preCommitSectorBatch2Inner(rt Runtime, params *PreCommitSectorBat rewardStats := requestCurrentEpochBlockReward(rt) pwrTotal := requestCurrentTotalPower(rt) - if !newBehaviour { + if !newBehaviour && len(sectorsDeals) > 0 { verifyDealsForActivation(rt, sectorsDeals) } diff --git a/actors/builtin/miner/miner_commitment_test.go b/actors/builtin/miner/miner_commitment_test.go index a2c24ae85..dcc29b30a 100644 --- a/actors/builtin/miner/miner_commitment_test.go +++ b/actors/builtin/miner/miner_commitment_test.go @@ -133,6 +133,7 @@ func TestCommitments(t *testing.T) { }) t.Run("deal space exceeds sector space", func(t *testing.T) { + t.Skip("TODO needs to be moved to ProveCommit") //TODO actor := newHarness(t, periodOffset) rt := builderForHarness(actor). WithBalance(bigBalance, big.Zero()).