-
Notifications
You must be signed in to change notification settings - Fork 83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: refactor vesting funds into a head and a tail #1636
base: master
Are you sure you want to change the base?
Conversation
1. In the test harness, check if we should vest every epoch. The queue should already be quantized. 2. Correctly handle the fact that we vest at the _end_ of an epoch in the cron vesting test.
Built on #1635. |
c0f87e1
to
c1c4df2
Compare
@@ -4464,25 +4460,6 @@ fn handle_proving_deadline( | |||
let state: State = rt.transaction(|state: &mut State, rt| { | |||
let policy = rt.policy(); | |||
|
|||
// Vesting rewards for a miner are quantized to every 12 hours and we can determine what those "vesting epochs" are. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to the end, see the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the benefit of moving this below ?
d4e6f8f
to
8c53bc7
Compare
This is significantly more than just "fixing #1594" so it probably requires a FIP update to FIP-0100. But, IMO, we should strongly consider this because without it, we'll be re-writing the vesting queue every deadline. I guess that isn't terrible in the grand scheme of things but.... it's not great. |
8c53bc7
to
accd9fc
Compare
This lets us efficiently take fees from vesting funds without loading/storing this object each time. It also lets us check if there are funds to vest without having to load any additional state, because the "next" batch of vesting funds are always stored in the root state object. If FIP-0100 passes, we'll likely want this change as we'll otherwise read/write the vesting funds queue on every deadline for every miner. fixes #1594
accd9fc
to
9565521
Compare
pub fn unlock_unvested_funds( | ||
/// Unlock all vested (first return value) then unlock unvested funds up to at most the | ||
/// specified target. | ||
pub fn unlock_vested_and_unvested_funds( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please note that changing the interface at the same time as the implementation like this is not the most friendly for review. I get that you are in cleanup mode and this is how it is. Decoupled changes at commit level would probably halve my "wtf are we doing again" moments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's not much I can do about that here, I'm changing the behavior from:
- Unlock unvested only, leaving unvested untouched.
- Unlock vested and unvested.
This didn't matter much before because the VestingFunds
had all the state locally (so we could just unlock vested, then unlock unvested). But it matters now because I need to read the "tail" which may be behind a CID, so we get better performance by doing it in one go.
I could have done this in two commits, but then I would have had to have implemented it the other way first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it matters now because I need to read the "tail" which may be behind a CID, so we get better performance by doing it in one go.
Yeah I'm questioning whether that performance is worth it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but then I would have had to have implemented it the other way first.
That's a good point
Ok(unlocked) | ||
} | ||
|
||
// Adds locked funds and unlocks everything that has already vested. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noting this second part looks like a behavior change. I can't see any problems with the new additional behavior as long as all the callers are doing the necessary book keeping with LockedFunds field
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok looks like this is just pushing down this coupled behavior to this level. Since only caller of this appears to be doing the same thing its not a real behavior change at all.
@@ -4464,25 +4460,6 @@ fn handle_proving_deadline( | |||
let state: State = rt.transaction(|state: &mut State, rt| { | |||
let policy = rt.policy(); | |||
|
|||
// Vesting rewards for a miner are quantized to every 12 hours and we can determine what those "vesting epochs" are. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the benefit of moving this below ?
|
||
Ok((from_vesting, from_balance)) | ||
Ok((to_burn, total_unlocked)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Despite not liking touching this code the change does read as correct.
1b29979
to
242e68e
Compare
This will save space when we have no vesting funds and, tbh, simplifies the code a bit. Also note: - I changed the return value of `load` to return a vector. I can make it work with iterators, but it's very... "rusty" (unreadable). - I made `can_vest` private.
242e68e
to
dfd6787
Compare
I think I've addressed all the feedback so far. |
current_epoch: ChainEpoch, | ||
vesting_sum: &TokenAmount, | ||
proving_period_start: ChainEpoch, | ||
spec: &VestSpec, | ||
) { | ||
) -> Result<TokenAmount, ActorError> { | ||
// Quantization is aligned with when regular cron will be invoked, in the last epoch of deadlines. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you sanity check this comment @Stebalien, it doesn't seem true to me; we offset
at proving_period_start
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's worse:
- We round up to the next proving period start (or 12 hours from then). So, deadline start not deadline end (as you noted).
- Then we unlock the epoch after that. I.e., we unlock everything where
vest_epoch < current_epoch
.
So, really, I think the actual unlock will happen the deadline after.
(I should write a better test)
// The "next" batch of vesting funds. | ||
head: VestingFund, | ||
// The rest of the vesting funds, if any. | ||
tail: Cid, // Vec<VestingFund> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still could be Optional<Cid>
so we could avoid storing the empty array CID when you get down to having nothing beyond the head left.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be, but I didn't think that was worth optimizing. Miners should almost never be in that state.
Documenting this and how a migration would work in here: filecoin-project/FIPs#1130 I've said that a migration shouldn't make any attempt to perform vesting in the case that it happens to put a |
Co-authored-by: Rod Vagg <[email protected]>
This lets us efficiently take fees from vesting funds without loading/storing this object each time. It also lets us check if there are funds to vest without having to load any additional state, because the "next" batch of vesting funds are always stored in the root state object.
If FIP-0100 passes, we'll likely want this change as we'll otherwise read/write the vesting funds queue on every deadline for every miner.
fixes #1594