diff --git a/abi/sector.go b/abi/sector.go index ecfb9ae7..c5802965 100644 --- a/abi/sector.go +++ b/abi/sector.go @@ -488,6 +488,16 @@ func (p RegisteredSealProof) ReplicaId(prover ActorID, sector SectorNumber, tick return bytesIntoFr32Safe(s.Sum(nil)), nil } +func (p RegisteredSealProof) IsSynthetic() bool { + _, ok := Synthetic[p] + return ok +} + +func (p RegisteredSealProof) IsNonInteractive() bool { + _, ok := NonInteractive[p] + return ok +} + type ProverID [32]byte // ProverID returns a 32 byte proverID used when computing ReplicaID diff --git a/builtin/methods.go b/builtin/methods.go index 8b57a498..e6cee9dd 100644 --- a/builtin/methods.go +++ b/builtin/methods.go @@ -243,6 +243,7 @@ var MethodsMiner = struct { // MovePartitionsExported abi.MethodNum ProveCommitSectors3 abi.MethodNum ProveReplicaUpdates3 abi.MethodNum + ProveCommitSectorsNI abi.MethodNum }{ MethodConstructor, 2, @@ -294,6 +295,7 @@ var MethodsMiner = struct { // MovePartitions: 33, 34, 35, + 36, } var MethodsVerifiedRegistry = struct { diff --git a/builtin/v14/gen/gen.go b/builtin/v14/gen/gen.go index 5b0e9f30..ea377673 100644 --- a/builtin/v14/gen/gen.go +++ b/builtin/v14/gen/gen.go @@ -218,6 +218,8 @@ func main() { miner.ReplicaUpdate2{}, miner.ExpirationExtension2{}, miner.SectorClaim{}, + miner.SectorNIActivationInfo{}, + miner.ProveCommitSectorsNIParams{}, ); err != nil { panic(err) } diff --git a/builtin/v14/miner/cbor_gen.go b/builtin/v14/miner/cbor_gen.go index 6dcaa5c9..9d9ce934 100644 --- a/builtin/v14/miner/cbor_gen.go +++ b/builtin/v14/miner/cbor_gen.go @@ -9550,3 +9550,440 @@ func (t *SectorClaim) UnmarshalCBOR(r io.Reader) (err error) { } return nil } + +var lengthBufSectorNIActivationInfo = []byte{134} + +func (t *SectorNIActivationInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write(lengthBufSectorNIActivationInfo); err != nil { + return err + } + + // t.SealingNumber (abi.SectorNumber) (uint64) + + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.SealingNumber)); err != nil { + return err + } + + // t.SealerID (abi.ActorID) (uint64) + + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.SealerID)); err != nil { + return err + } + + // t.SealedCID (cid.Cid) (struct) + + if err := cbg.WriteCid(cw, t.SealedCID); err != nil { + return xerrors.Errorf("failed to write cid field t.SealedCID: %w", err) + } + + // t.SectorNumber (abi.SectorNumber) (uint64) + + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.SectorNumber)); err != nil { + return err + } + + // t.SealRandEpoch (abi.ChainEpoch) (int64) + if t.SealRandEpoch >= 0 { + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.SealRandEpoch)); err != nil { + return err + } + } else { + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.SealRandEpoch-1)); err != nil { + return err + } + } + + // t.Expiration (abi.ChainEpoch) (int64) + if t.Expiration >= 0 { + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Expiration)); err != nil { + return err + } + } else { + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.Expiration-1)); err != nil { + return err + } + } + + return nil +} + +func (t *SectorNIActivationInfo) UnmarshalCBOR(r io.Reader) (err error) { + *t = SectorNIActivationInfo{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 6 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.SealingNumber (abi.SectorNumber) (uint64) + + { + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.SealingNumber = abi.SectorNumber(extra) + + } + // t.SealerID (abi.ActorID) (uint64) + + { + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.SealerID = abi.ActorID(extra) + + } + // t.SealedCID (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(cr) + if err != nil { + return xerrors.Errorf("failed to read cid field t.SealedCID: %w", err) + } + + t.SealedCID = c + + } + // t.SectorNumber (abi.SectorNumber) (uint64) + + { + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.SectorNumber = abi.SectorNumber(extra) + + } + // t.SealRandEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + var extraI int64 + 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 overflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SealRandEpoch = abi.ChainEpoch(extraI) + } + // t.Expiration (abi.ChainEpoch) (int64) + { + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + var extraI int64 + 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 overflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Expiration = abi.ChainEpoch(extraI) + } + return nil +} + +var lengthBufProveCommitSectorsNIParams = []byte{134} + +func (t *ProveCommitSectorsNIParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write(lengthBufProveCommitSectorsNIParams); err != nil { + return err + } + + // t.Sectors ([]miner.SectorNIActivationInfo) (slice) + if len(t.Sectors) > 8192 { + return xerrors.Errorf("Slice value in field t.Sectors was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Sectors))); err != nil { + return err + } + for _, v := range t.Sectors { + if err := v.MarshalCBOR(cw); err != nil { + return err + } + + } + + // t.AggregateProof ([]uint8) (slice) + if len(t.AggregateProof) > 2097152 { + return xerrors.Errorf("Byte array in field t.AggregateProof was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.AggregateProof))); err != nil { + return err + } + + if _, err := cw.Write(t.AggregateProof); err != nil { + return err + } + + // t.SealProofType (abi.RegisteredSealProof) (int64) + if t.SealProofType >= 0 { + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.SealProofType)); err != nil { + return err + } + } else { + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.SealProofType-1)); err != nil { + return err + } + } + + // t.AggregateProofType (abi.RegisteredAggregationProof) (int64) + if t.AggregateProofType >= 0 { + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.AggregateProofType)); err != nil { + return err + } + } else { + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.AggregateProofType-1)); err != nil { + return err + } + } + + // t.ProvingDeadline (uint64) (uint64) + + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ProvingDeadline)); err != nil { + return err + } + + // t.RequireActivationSuccess (bool) (bool) + if err := cbg.WriteBool(w, t.RequireActivationSuccess); err != nil { + return err + } + return nil +} + +func (t *ProveCommitSectorsNIParams) UnmarshalCBOR(r io.Reader) (err error) { + *t = ProveCommitSectorsNIParams{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 6 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Sectors ([]miner.SectorNIActivationInfo) (slice) + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + + if extra > 8192 { + 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([]SectorNIActivationInfo, extra) + } + + for i := 0; i < int(extra); i++ { + { + var maj byte + var extra uint64 + var err error + _ = maj + _ = extra + _ = err + + { + + if err := t.Sectors[i].UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Sectors[i]: %w", err) + } + + } + + } + } + // t.AggregateProof ([]uint8) (slice) + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + + if extra > 2097152 { + return fmt.Errorf("t.AggregateProof: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.AggregateProof = make([]uint8, extra) + } + + if _, err := io.ReadFull(cr, t.AggregateProof); err != nil { + return err + } + + // t.SealProofType (abi.RegisteredSealProof) (int64) + { + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + var extraI int64 + 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 overflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SealProofType = abi.RegisteredSealProof(extraI) + } + // t.AggregateProofType (abi.RegisteredAggregationProof) (int64) + { + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + var extraI int64 + 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 overflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.AggregateProofType = abi.RegisteredAggregationProof(extraI) + } + // t.ProvingDeadline (uint64) (uint64) + + { + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.ProvingDeadline = uint64(extra) + + } + // t.RequireActivationSuccess (bool) (bool) + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.RequireActivationSuccess = false + case 21: + t.RequireActivationSuccess = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + return nil +} diff --git a/builtin/v14/miner/methods.go b/builtin/v14/miner/methods.go index d79549cf..4729cf0f 100644 --- a/builtin/v14/miner/methods.go +++ b/builtin/v14/miner/methods.go @@ -62,4 +62,5 @@ var Methods = map[abi.MethodNum]builtin.MethodMeta{ // 33 MovePartitions 34: {"ProveCommitSectors3", *new(func(*ProveCommitSectors3Params) *ProveCommitSectors3Return)}, // ProveCommitSectors3 35: {"ProveReplicaUpdates3", *new(func(*ProveReplicaUpdates3Params) *ProveReplicaUpdates3Return)}, // ProveReplicaUpdates3 + 36: {"ProveCommitSectorsNI", *new(func(*ProveCommitSectorsNIParams) *abi.EmptyValue)}, // ProveCommitSectorsNI } diff --git a/builtin/v14/miner/miner_types.go b/builtin/v14/miner/miner_types.go index 1570c8c1..b1515451 100644 --- a/builtin/v14/miner/miner_types.go +++ b/builtin/v14/miner/miner_types.go @@ -496,3 +496,26 @@ type SectorReturn = []PieceReturn // PieceReturn represents a result for each piece for the sector that was notified. type PieceReturn = bool // Accepted = true + +// SectorNIActivationInfo is the information needed to activate a sector with a "zero" replica. +type SectorNIActivationInfo struct { + SealingNumber abi.SectorNumber // Sector number used to generate replica id + SealerID abi.ActorID // Must be set to ID of receiving actor for now + SealedCID cid.Cid // CommR + SectorNumber abi.SectorNumber // Unique id of sector in actor state + SealRandEpoch abi.ChainEpoch + Expiration abi.ChainEpoch +} + +// ProveCommitSectorsNIParams is the parameters for non-interactive prove committing of sectors +// via the miner actor method ProveCommitSectorsNI. +type ProveCommitSectorsNIParams struct { + Sectors []SectorNIActivationInfo // Information about sealing of each sector + AggregateProof []byte // Aggregate proof for all sectors + SealProofType abi.RegisteredSealProof // Proof type for each seal (must be an NI-PoRep variant) + AggregateProofType abi.RegisteredAggregationProof // Proof type for aggregation + ProvingDeadline uint64 // The Window PoST deadline index at which to schedule the new sectors + RequireActivationSuccess bool // Whether to abort if any sector activation fails +} + +type ProveCommitSectorsNIReturn = BatchReturn diff --git a/builtin/v14/miner/miner_types_test.go b/builtin/v14/miner/miner_types_test.go new file mode 100644 index 00000000..4068ba27 --- /dev/null +++ b/builtin/v14/miner/miner_types_test.go @@ -0,0 +1,94 @@ +package miner + +import ( + "bytes" + "encoding/hex" + "testing" + + "github.com/filecoin-project/go-state-types/abi" + cid "github.com/ipfs/go-cid" + "github.com/stretchr/testify/require" +) + +// Tests to match with Rust fil_actor_miner::serialization + +func TestSerializationSlaimAllocationsParams(t *testing.T) { + testCases := []struct { + params ProveCommitSectorsNIParams + hex string + }{ + { + params: ProveCommitSectorsNIParams{ + Sectors: nil, + AggregateProof: nil, + SealProofType: abi.RegisteredSealProof_StackedDrg32GiBV1_1, + AggregateProofType: abi.RegisteredAggregationProof_SnarkPackV2, + ProvingDeadline: 2, + RequireActivationSuccess: false, + }, + // [[],byte[],8,1,2,false] + hex: "868040080102f4", + }, + { + params: ProveCommitSectorsNIParams{ + Sectors: []SectorNIActivationInfo{{ + SealingNumber: 1, + SealerID: 2, + SealedCID: cid.MustParse("bagboea4seaaqa"), + SectorNumber: 3, + SealRandEpoch: 4, + Expiration: 5, + }}, + SealProofType: abi.RegisteredSealProof_StackedDrg32GiBV1_2_Feat_NiPoRep, + AggregateProof: []byte{0xde, 0xad, 0xbe, 0xef}, + AggregateProofType: abi.RegisteredAggregationProof_SnarkPackV2, + ProvingDeadline: 6, + RequireActivationSuccess: true, + }, + // [[[1,2,bagboea4seaaqa,3,4,5]],byte[deadbeef],18,1,6,true] + hex: "8681860102d82a49000182e2039220010003040544deadbeef120106f5", + }, + { + params: ProveCommitSectorsNIParams{ + Sectors: []SectorNIActivationInfo{ + { + SealingNumber: 1, + SealerID: 2, + SealedCID: cid.MustParse("bagboea4seaaqa"), + SectorNumber: 3, + SealRandEpoch: 4, + Expiration: 5, + }, + { + SealingNumber: 6, + SealerID: 7, + SealedCID: cid.MustParse("bagboea4seaaqc"), + SectorNumber: 8, + SealRandEpoch: 9, + Expiration: 10, + }, + }, + SealProofType: abi.RegisteredSealProof_StackedDrg32GiBV1_2_Feat_NiPoRep, + AggregateProof: []byte{0xde, 0xad, 0xbe, 0xef}, + AggregateProofType: abi.RegisteredAggregationProof_SnarkPackV2, + ProvingDeadline: 11, + RequireActivationSuccess: false, + }, + // [[[1,2,bagboea4seaaqa,3,4,5],[6,7,bagboea4seaaqc,8,9,10]],byte[deadbeef],18,1,11,false] + hex: "8682860102d82a49000182e20392200100030405860607d82a49000182e2039220010108090a44deadbeef12010bf4", + }, + } + + for _, tc := range testCases { + t.Run("", func(t *testing.T) { + req := require.New(t) + + var buf bytes.Buffer + req.NoError(tc.params.MarshalCBOR(&buf)) + req.Equal(tc.hex, hex.EncodeToString(buf.Bytes())) + var rt ProveCommitSectorsNIParams + req.NoError(rt.UnmarshalCBOR(&buf)) + req.Equal(tc.params, rt) + }) + } +} diff --git a/builtin/v14/miner/policy.go b/builtin/v14/miner/policy.go index 22390079..ccbf7667 100644 --- a/builtin/v14/miner/policy.go +++ b/builtin/v14/miner/policy.go @@ -107,6 +107,12 @@ var MaxPreCommitRandomnessLookback = builtin.EpochsInDay + ChainFinality // PARA // (2) prevents a miner attempting a long fork in the past to insert a pre-commitment after seeing the challenge. var PreCommitChallengeDelay = abi.ChainEpoch(150) // PARAM_SPEC +// Maximum number of epochs within which to fetch a valid seal randomness from the chain for +// a non-interactive PoRep proof. This balances the need to tie the seal to a particular chain with +// but makes allowance for service providers to offer pre-sealed sectors within a larger window of +// time. +var MaxProveCommitNiLookback = abi.ChainEpoch(180 * builtin.EpochsInDay) // PARAM_SPEC + // Lookback from the deadline's challenge window opening from which to sample chain randomness for the WindowPoSt challenge seed. // This means that deadline windows can be non-overlapping (which make the programming simpler) without requiring a // miner to wait for chain stability during the challenge window.