Skip to content
This repository has been archived by the owner on Jun 6, 2023. It is now read-only.

Commit

Permalink
Randomize deadline assignment
Browse files Browse the repository at this point in the history
This commit randomizes deadline assignment by starting to open new partitions

fixes #432
  • Loading branch information
Stebalien committed Aug 28, 2020
1 parent 41fc1fe commit c8874e5
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 16 deletions.
9 changes: 5 additions & 4 deletions actors/builtin/miner/deadline_assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func (dai *deadlineAssignmentInfo) maxPartitionsReached(partitionSize, maxPartit
}

type deadlineAssignmentHeap struct {
offset uint64
maxPartitions uint64
partitionSize uint64
deadlines []*deadlineAssignmentInfo
Expand Down Expand Up @@ -155,10 +156,8 @@ func (dah *deadlineAssignmentHeap) Less(i, j int) bool {
return a.liveSectors < b.liveSectors
}

// Finally, fallback on the deadline index.
// TODO: Randomize by index instead of simply sorting.
// https://github.com/filecoin-project/specs-actors/issues/432
return a.index < b.index
// Finally, fallback on the deadline index, starting at an offset.
return (uint64(a.index)-dah.offset)%WPoStPeriodDeadlines < (uint64(b.index)-dah.offset)%WPoStPeriodDeadlines
}

func (dah *deadlineAssignmentHeap) Push(x interface{}) {
Expand All @@ -175,13 +174,15 @@ func (dah *deadlineAssignmentHeap) Pop() interface{} {
// Assigns partitions to deadlines, first filling partial partitions, then
// adding new partitions to deadlines with the fewest live sectors.
func assignDeadlines(
offset uint64,
maxPartitions uint64,
partitionSize uint64,
deadlines *[WPoStPeriodDeadlines]*Deadline,
sectors []*SectorOnChainInfo,
) (changes [WPoStPeriodDeadlines][]*SectorOnChainInfo, err error) {
// Build a heap
dlHeap := deadlineAssignmentHeap{
offset: offset,
maxPartitions: maxPartitions,
partitionSize: partitionSize,
deadlines: make([]*deadlineAssignmentInfo, 0, len(deadlines)),
Expand Down
19 changes: 11 additions & 8 deletions actors/builtin/miner/deadline_assignment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,22 @@ func TestDeadlineAssignment(t *testing.T) {

type testCase struct {
sectors uint64
offset uint64
deadlines [WPoStPeriodDeadlines]*deadline
}

testCases := []testCase{{
// Even assignment and striping.
sectors: 10,
offset: 1,
deadlines: [WPoStPeriodDeadlines]*deadline{
0: {
1: {
expectSectors: []uint64{
0, 1, 2, 3,
8, 9,
},
},
1: {
2: {
expectSectors: []uint64{
4, 5, 6, 7,
},
Expand All @@ -54,12 +56,13 @@ func TestDeadlineAssignment(t *testing.T) {
}, {
// Assign to deadline with least number of live partitions.
sectors: 1,
offset: 6,
deadlines: [WPoStPeriodDeadlines]*deadline{
0: {
6: {
// 2 live partitions. +1 would add another.
liveSectors: 8,
},
1: {
7: {
// 2 live partitions. +1 wouldn't add another.
// 1 dead partition.
liveSectors: 7,
Expand Down Expand Up @@ -152,7 +155,7 @@ func TestDeadlineAssignment(t *testing.T) {
for i := range sectors {
sectors[i] = &SectorOnChainInfo{SectorNumber: abi.SectorNumber(i)}
}
assignment, err := assignDeadlines(maxPartitions, partitionSize, &deadlines, sectors)
assignment, err := assignDeadlines(tc.offset, maxPartitions, partitionSize, &deadlines, sectors)
require.NoError(t, err)
for i, sectors := range assignment {
dl := tc.deadlines[i]
Expand Down Expand Up @@ -192,7 +195,7 @@ func TestMaxPartitionsPerDeadline(t *testing.T) {
sectors[i] = &SectorOnChainInfo{SectorNumber: abi.SectorNumber(i)}
}

_, err := assignDeadlines(maxPartitions, partitionSize, &deadlines, sectors)
_, err := assignDeadlines(0, maxPartitions, partitionSize, &deadlines, sectors)
require.Error(t, err)
})

Expand All @@ -212,7 +215,7 @@ func TestMaxPartitionsPerDeadline(t *testing.T) {
sectors[i] = &SectorOnChainInfo{SectorNumber: abi.SectorNumber(i)}
}

deadlineToSectors, err := assignDeadlines(maxPartitions, partitionSize, &deadlines, sectors)
deadlineToSectors, err := assignDeadlines(0, maxPartitions, partitionSize, &deadlines, sectors)
require.NoError(t, err)

for _, sectors := range deadlineToSectors {
Expand All @@ -236,7 +239,7 @@ func TestMaxPartitionsPerDeadline(t *testing.T) {
sectors[i] = &SectorOnChainInfo{SectorNumber: abi.SectorNumber(i)}
}

_, err := assignDeadlines(maxPartitions, partitionSize, &deadlines, sectors)
_, err := assignDeadlines(0, maxPartitions, partitionSize, &deadlines, sectors)
require.Error(t, err)
})
}
10 changes: 8 additions & 2 deletions actors/builtin/miner/miner_actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,13 @@ func (a Actor) ConfirmSectorProofsValid(rt Runtime, params *builtin.ConfirmSecto
rt.Abortf(exitcode.ErrIllegalArgument, "all prove commits failed to validate")
}

buf := new(bytes.Buffer)
receiver := rt.Message().Receiver()
err = receiver.MarshalCBOR(buf)
assignmentRandomness := binary.BigEndian.Uint64(rt.GetRandomnessFromBeacon(
crypto.DomainSeparationTag_WindowedPoStDeadlineAssignment, rt.CurrEpoch(), buf.Bytes(),
))

var newPower PowerPair
totalPledge := big.Zero()
depositToUnlock := big.Zero()
Expand Down Expand Up @@ -804,8 +811,7 @@ func (a Actor) ConfirmSectorProofsValid(rt Runtime, params *builtin.ConfirmSecto

err = st.DeletePrecommittedSectors(store, newSectorNos...)
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to delete precommited sectors")

newPower, err = st.AssignSectorsToDeadlines(store, rt.CurrEpoch(), newSectors, info.WindowPoStPartitionSectors, info.SectorSize)
newPower, err = st.AssignSectorsToDeadlines(store, rt.CurrEpoch(), assignmentRandomness, newSectors, info.WindowPoStPartitionSectors, info.SectorSize)
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to assign new sectors to deadlines")

// Add sector and pledge lock-up to miner state
Expand Down
3 changes: 2 additions & 1 deletion actors/builtin/miner/miner_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ func (st *State) RescheduleSectorExpirations(
func (st *State) AssignSectorsToDeadlines(
store adt.Store,
currentEpoch abi.ChainEpoch,
randomness uint64,
sectors []*SectorOnChainInfo,
partitionSize uint64,
sectorSize abi.SectorSize,
Expand Down Expand Up @@ -523,7 +524,7 @@ func (st *State) AssignSectorsToDeadlines(
}

activatedPower := NewPowerPairZero()
deadlineToSectors, err := assignDeadlines(MaxPartitionsPerDeadline, partitionSize, &deadlineArr, sectors)
deadlineToSectors, err := assignDeadlines(randomness, MaxPartitionsPerDeadline, partitionSize, &deadlineArr, sectors)
if err != nil {
return NewPowerPairZero(), xerrors.Errorf("failed to assign sectors to deadlines: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion actors/builtin/miner/miner_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ func TestSectorAssignment(t *testing.T) {
t.Run("assign sectors to deadlines", func(t *testing.T) {
harness := constructStateHarness(t, abi.ChainEpoch(0))

newPower, err := harness.s.AssignSectorsToDeadlines(harness.store, 0, sectorInfos,
newPower, err := harness.s.AssignSectorsToDeadlines(harness.store, 0, 0, sectorInfos,
partitionSectors, sectorSize)

sectorArr := sectorsArr(t, harness.store, sectorInfos)
Expand Down
4 changes: 4 additions & 0 deletions actors/builtin/miner/miner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3526,6 +3526,10 @@ func (h *actorHarness) confirmSectorProofsValid(rt *mock.Runtime, conf proveComm

// expected pledge is the sum of initial pledges
if len(validPrecommits) > 0 {
randBuf := bytes.NewBuffer(nil)
require.NoError(h.t, h.receiver.MarshalCBOR(randBuf))
rt.ExpectGetRandomnessBeacon(crypto.DomainSeparationTag_WindowedPoStDeadlineAssignment, rt.Epoch(), randBuf.Bytes(), make([]byte, 32))

expectPledge := big.Zero()

expectQAPower := big.Zero()
Expand Down

0 comments on commit c8874e5

Please sign in to comment.