chore: add consensus-key guard when processing deposits#380
chore: add consensus-key guard when processing deposits#380matthias-wright wants to merge 5 commits into
Conversation
|
I think this is a good partial fix for #339. The stale queued-deposit lifecycle can still reach a no-account path: a top-up can be queued while In that case this branch only logs and skips the deposit: let Some(mut account) = state.get_account(&node_pubkey_bytes).cloned() else {
warn!("Deposit request has no corresponding account, skipping: {request:?}");
continue;
};That means the queued top-up is not processed against its original account lifecycle and is not refunded either. I think the remaining invariant should be that a queued deposit must either be processed against its original account lifecycle or refunded. |
d9751c3 to
5112dc7
Compare
|
Thanks, the new commits fix the no-account queued-deposit path I commented on. One remaining edge case: if a later replacement deposit recreates an inactive placeholder for the same node key and same consensus key but different withdrawal credentials before the stale old queued deposit is popped, FIFO still pops the old deposit first, but the replacement placeholder already exists. The no-account branch does not fire, and the new consensus-key guard passes. The stale deposit can then be processed against the replacement account and use So the no-account issue looks fixed, but I think the consume-time binding should also prove the current account belongs to the same account lifecycle that accepted the queued deposit, for example by checking withdrawal credentials / expected deposit index, or otherwise refund the queued deposit to |
5112dc7 to
81e233d
Compare
|
Update(81e233d):
|
|
Thanks, I tested latest 81e233d locally. The refund-destination fix works for the refund path: if the stale queued deposit is rejected/refunded, it now refunds to request.withdrawal_credentials. However, I think the successful-processing path is still not bound to the original account lifecycle. I modified the new same-key replacement regression test so the stale deposit amount is in range instead of below minimum. In that case the stale deposit does not enter the refund path. The current account exists, the consensus key matches, and the deposit is accepted as a valid new-validator deposit against the replacement placeholder. The test passed while asserting that the replacement account was credited with the stale deposit amount and retained the replacement withdrawal credentials. So 81e233d fixes wrong refund destination, but it does not prevent an in-range stale queued deposit from being successfully applied to a same-node-key/same-consensus-key replacement account. I think consume-time processing still needs to bind to the same account lifecycle that accepted the queued deposit, for example by checking withdrawal credentials / expected deposit index / explicit account generation, or refunding when that binding fails. |
|
I'm working on a refactor of the deposit and withdrawal processing (out of scope for this audit) that fixes #339, so I will close this PR. |
Builds on #377 (which builds on #276 and #275).
Addresses #339.
Changes:
Note: This guard is purely defensive,
minimum indefinitely. This is fixed by:
has_pending_depositaccount only if its queued deposit could bring it back into[min, max]; otherwise enforce now. Zero-balance new-validator placeholdersstay excluded.
test_pending_topup_does_not_evade_minimum_stake_increase.