Skip to content

Commit 6d9ebf8

Browse files
committed
fix(fip-0118): use migration epoch as the stream start
1 parent c3285ac commit 6d9ebf8

3 files changed

Lines changed: 66 additions & 41 deletions

File tree

builtin/v19/migration/reward.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,23 @@ type rewardMigrator struct {
2323
swaActor address.Address
2424
}
2525

26-
func newRewardMigrator(config RewardMigrationConfig, outCodeCID cid.Cid) (*rewardMigrator, error) {
27-
streams, accruals, err := reward19.ValidateMigrationStreams(config.Streams, config.ActivationEpoch)
26+
func newRewardMigrator(config RewardMigrationConfig, activationEpoch abi.ChainEpoch, outCodeCID cid.Cid) (*rewardMigrator, error) {
27+
streamParams := make([]reward19.RegisterStreamParams, len(config.Streams))
28+
for i, stream := range config.Streams {
29+
streamParams[i] = reward19.RegisterStreamParams{
30+
ID: stream.ID,
31+
Weight: reward19.WeightRecord{
32+
VStart: stream.Weight.VStart,
33+
Slope: stream.Weight.Slope,
34+
TStart: activationEpoch,
35+
Floor: stream.Weight.Floor,
36+
Cap: stream.Weight.Cap,
37+
},
38+
Distribution: stream.Distribution,
39+
ActivationEpoch: activationEpoch,
40+
}
41+
}
42+
streams, accruals, err := reward19.ValidateMigrationStreams(streamParams, activationEpoch)
2843
if err != nil {
2944
return nil, xerrors.Errorf("invalid reward migration streams: %w", err)
3045
}

builtin/v19/migration/reward_test.go

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,24 @@ func migrationIDAddress(t *testing.T, id uint64) address.Address {
2525
return addr
2626
}
2727

28-
func validRewardMigrationConfig(t *testing.T, activationEpoch abi.ChainEpoch) RewardMigrationConfig {
28+
func validRewardMigrationConfig(t *testing.T) RewardMigrationConfig {
2929
t.Helper()
3030
pct := reward19.Denom / 100
3131
return RewardMigrationConfig{
32-
ActivationEpoch: activationEpoch,
3332
SWATimelockEpochs: 20_160,
3433
SWAActor: migrationIDAddress(t, 100),
35-
Streams: []reward19.RegisterStreamParams{
34+
Streams: []RewardMigrationStream{
3635
{
37-
ID: 1,
38-
Weight: reward19.WeightRecord{VStart: 95 * pct, Slope: -1, TStart: activationEpoch, Floor: 50 * pct, Cap: 95 * pct},
39-
ActivationEpoch: activationEpoch,
36+
ID: 1,
37+
Weight: RewardMigrationWeight{VStart: 95 * pct, Slope: -1, Floor: 50 * pct, Cap: 95 * pct},
4038
},
4139
{
4240
ID: 2,
43-
Weight: reward19.WeightRecord{VStart: 5 * pct, Slope: 1, TStart: activationEpoch, Floor: 5 * pct, Cap: 10 * pct},
41+
Weight: RewardMigrationWeight{VStart: 5 * pct, Slope: 1, Floor: 5 * pct, Cap: 10 * pct},
4442
Distribution: &reward19.DistributionInit{
4543
Writer: migrationIDAddress(t, 101),
4644
Shares: []reward19.RecipientShare{{Recipient: migrationIDAddress(t, 102), Share: reward19.Denom}},
4745
},
48-
ActivationEpoch: activationEpoch,
4946
},
5047
},
5148
}
@@ -74,9 +71,9 @@ func TestRewardMigration(t *testing.T) {
7471
req.NoError(err)
7572

7673
activationEpoch := abi.ChainEpoch(100)
77-
config := validRewardMigrationConfig(t, activationEpoch)
74+
config := validRewardMigrationConfig(t)
7875
outCodeCID := cid.MustParse("bafy2bzaca4aaaaaaaaaqk")
79-
migrator, err := newRewardMigrator(config, outCodeCID)
76+
migrator, err := newRewardMigrator(config, activationEpoch, outCodeCID)
8077
req.NoError(err)
8178
result, err := migrator.MigrateState(ctx, store, migration.ActorMigrationInput{Address: address.TestAddress, Head: inHead})
8279
req.NoError(err)
@@ -104,10 +101,22 @@ func TestRewardMigration(t *testing.T) {
104101
req.NoError(err)
105102
req.Len(streams.Streams, 2)
106103
req.Equal(reward19.StreamID(1), streams.Streams[0].ID)
107-
req.Equal(config.Streams[0].Weight, streams.Streams[0].Weight)
104+
req.Equal(reward19.WeightRecord{
105+
VStart: config.Streams[0].Weight.VStart,
106+
Slope: config.Streams[0].Weight.Slope,
107+
TStart: activationEpoch,
108+
Floor: config.Streams[0].Weight.Floor,
109+
Cap: config.Streams[0].Weight.Cap,
110+
}, streams.Streams[0].Weight)
108111
req.Nil(streams.Streams[0].Distribution)
109112
req.Equal(reward19.StreamID(2), streams.Streams[1].ID)
110-
req.Equal(config.Streams[1].Weight, streams.Streams[1].Weight)
113+
req.Equal(reward19.WeightRecord{
114+
VStart: config.Streams[1].Weight.VStart,
115+
Slope: config.Streams[1].Weight.Slope,
116+
TStart: activationEpoch,
117+
Floor: config.Streams[1].Weight.Floor,
118+
Cap: config.Streams[1].Weight.Cap,
119+
}, streams.Streams[1].Weight)
111120
req.Equal(config.Streams[1].Distribution.Writer, streams.Streams[1].Distribution.Writer)
112121
req.Equal(config.Streams[1].Distribution.Shares, streams.Streams[1].Distribution.Shares)
113122
req.Empty(streams.Tombstones)
@@ -121,7 +130,8 @@ func TestRewardMigrationDropsStoredRewardTotals(t *testing.T) {
121130
store := cbor.NewMemCborStore()
122131
activationEpoch := abi.ChainEpoch(100)
123132
migrator, err := newRewardMigrator(
124-
validRewardMigrationConfig(t, activationEpoch),
133+
validRewardMigrationConfig(t),
134+
activationEpoch,
125135
cid.MustParse("bafy2bzaca4aaaaaaaaaqk"),
126136
)
127137
req.NoError(err)
@@ -164,23 +174,21 @@ func TestRewardMigrationDropsStoredRewardTotals(t *testing.T) {
164174
func TestNewRewardMigratorAcceptsAlternativeBootstrapWeights(t *testing.T) {
165175
activationEpoch := abi.ChainEpoch(100)
166176
pct := reward19.Denom / 100
167-
config := validRewardMigrationConfig(t, activationEpoch)
168-
config.Streams[0].Weight = reward19.WeightRecord{
177+
config := validRewardMigrationConfig(t)
178+
config.Streams[0].Weight = RewardMigrationWeight{
169179
VStart: 80 * pct,
170180
Slope: -1,
171-
TStart: activationEpoch,
172181
Floor: 60 * pct,
173182
Cap: 80 * pct,
174183
}
175-
config.Streams[1].Weight = reward19.WeightRecord{
184+
config.Streams[1].Weight = RewardMigrationWeight{
176185
VStart: 20 * pct,
177186
Slope: 1,
178-
TStart: activationEpoch,
179187
Floor: 10 * pct,
180188
Cap: 20 * pct,
181189
}
182190

183-
_, err := newRewardMigrator(config, cid.MustParse("bafy2bzaca4aaaaaaaaaqk"))
191+
_, err := newRewardMigrator(config, activationEpoch, cid.MustParse("bafy2bzaca4aaaaaaaaaqk"))
184192
require.NoError(t, err)
185193
}
186194

@@ -192,20 +200,6 @@ func TestNewRewardMigratorRejectsInvalidConfig(t *testing.T) {
192200
mutate func(*RewardMigrationConfig)
193201
expected string
194202
}{
195-
{
196-
name: "activation epoch mismatch",
197-
mutate: func(config *RewardMigrationConfig) {
198-
config.Streams[0].ActivationEpoch++
199-
},
200-
expected: "activation epoch 101 does not match upgrade epoch 100",
201-
},
202-
{
203-
name: "weight start mismatch",
204-
mutate: func(config *RewardMigrationConfig) {
205-
config.Streams[1].Weight.TStart++
206-
},
207-
expected: "weight start 101 does not match upgrade epoch 100",
208-
},
209203
{
210204
name: "wrong stream count",
211205
mutate: func(config *RewardMigrationConfig) {
@@ -272,9 +266,9 @@ func TestNewRewardMigratorRejectsInvalidConfig(t *testing.T) {
272266

273267
for _, tc := range testCases {
274268
t.Run(tc.name, func(t *testing.T) {
275-
config := validRewardMigrationConfig(t, activationEpoch)
269+
config := validRewardMigrationConfig(t)
276270
tc.mutate(&config)
277-
_, err := newRewardMigrator(config, outCodeCID)
271+
_, err := newRewardMigrator(config, activationEpoch, outCodeCID)
278272
require.ErrorContains(t, err, tc.expected)
279273
})
280274
}

builtin/v19/migration/top.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,24 @@ import (
2121
)
2222

2323
type RewardMigrationConfig struct {
24-
ActivationEpoch abi.ChainEpoch
2524
SWATimelockEpochs abi.ChainEpoch
2625
SWAActor address.Address
27-
Streams []reward19.RegisterStreamParams
26+
Streams []RewardMigrationStream
27+
}
28+
29+
// RewardMigrationStream defines a bootstrap stream independently of its activation epoch.
30+
type RewardMigrationStream struct {
31+
ID reward19.StreamID
32+
Weight RewardMigrationWeight
33+
Distribution *reward19.DistributionInit
34+
}
35+
36+
// RewardMigrationWeight defines a bootstrap weigh independently of its start epoch.
37+
type RewardMigrationWeight struct {
38+
VStart uint64
39+
Slope int64
40+
Floor uint64
41+
Cap uint64
2842
}
2943

3044
// MigrateStateTree Migrates the filecoin state tree starting from the global state tree and upgrading all actor state.
@@ -109,11 +123,13 @@ func MigrateStateTree(ctx context.Context, store cbor.IpldStore, newManifestCID
109123
if !ok {
110124
return cid.Undef, xerrors.Errorf("code cid for reward actor not found in new manifest")
111125
}
112-
rewardMigrator, err := newRewardMigrator(rewardConfig, reward19CID)
126+
activationEpoch := priorEpoch + 1
127+
rewardMigrator, err := newRewardMigrator(rewardConfig, activationEpoch, reward19CID)
113128
if err != nil {
114129
return cid.Undef, xerrors.Errorf("failed to create reward migrator: %w", err)
115130
}
116-
migrations[reward18CID] = migration.CachedMigration(cache, *rewardMigrator)
131+
// The output depends on priorEpoch as well as the actor head, so it cannot use the head-only migration cache.
132+
migrations[reward18CID] = *rewardMigrator
117133

118134
if len(migrations)+len(deferredCodeIDs) != len(oldManifestData.Entries) {
119135
return cid.Undef, xerrors.Errorf("incomplete migration specification with %d code CIDs, need %d", len(migrations)+len(deferredCodeIDs), len(oldManifestData.Entries))

0 commit comments

Comments
 (0)