Skip to content

Commit 5e66222

Browse files
chore: check for state slot at commit time (#60)
* good-progress-it-compiles * more-cleanups * getting-there * found-a-few-edge-cases * saving-progress * some-cleanups * rust-everything-seems-to-work * integration-test-typescript-fix * nit-comment * more-cleanups * fees-naming-clarifications * todos * comments-nits * slot-check * done * fix: integration tests * chore: format --------- Co-authored-by: Gabriele Picco <piccogabriele@gmail.com>
1 parent d442e13 commit 5e66222

File tree

10 files changed

+400
-2934
lines changed

10 files changed

+400
-2934
lines changed

src/error.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ pub enum DlpError {
2929
InvalidWhitelistProgramConfig = 10,
3030
#[error("Account already undelegated")]
3131
AlreadyUndelegated = 11,
32+
#[error("Committed state slot is outdated")]
33+
OutdatedSlot = 12,
3234
#[error("Computation overflow detected")]
33-
Overflow = 12,
35+
Overflow = 13,
3436
}
3537

3638
impl From<DlpError> for ProgramError {

src/processor/commit_state.rs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use solana_program::program::invoke;
1616
use solana_program::program_error::ProgramError;
1717
use solana_program::system_instruction::transfer;
1818
use solana_program::system_program;
19-
use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, msg, pubkey::Pubkey};
19+
use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};
2020

2121
/// Commit a new state of a delegated Pda
2222
///
@@ -50,6 +50,26 @@ pub fn process_commit_state(
5050
load_initialized_validator_fees_vault(validator, validator_fees_vault, false)?;
5151
load_program(system_program, system_program::id())?;
5252

53+
// Read delegation metadata
54+
let mut delegation_metadata_data = delegation_metadata_account.try_borrow_mut_data()?;
55+
let mut delegation_metadata =
56+
DelegationMetadata::try_from_bytes_with_discriminator(&delegation_metadata_data)?;
57+
58+
// Once the account is marked as undelegatable, any subsequent commit should fail
59+
if delegation_metadata.is_undelegatable {
60+
return Err(DlpError::AlreadyUndelegated.into());
61+
}
62+
63+
// If the commit slot is greater than the last update slot, we can proceed
64+
// If slot is equal or less, we simply do not commit
65+
if commit_record_slot <= delegation_metadata.last_update_external_slot {
66+
return Err(DlpError::OutdatedSlot.into());
67+
}
68+
69+
// Update delegation metadata undelegation flag
70+
delegation_metadata.is_undelegatable = args.allow_undelegation;
71+
delegation_metadata.to_bytes_with_discriminator(&mut delegation_metadata_data.as_mut())?;
72+
5373
// Load delegation record
5474
let delegation_record_data = delegation_record_account.try_borrow_data()?;
5575
let delegation_record =
@@ -85,7 +105,6 @@ pub fn process_commit_state(
85105
let program_config_data = program_config_account.try_borrow_data()?;
86106
let program_config =
87107
ProgramConfig::try_from_bytes_with_discriminator(&program_config_data)?;
88-
msg!("Program Config: {:?}", program_config);
89108
if !program_config.approved_validators.contains(validator.key) {
90109
return Err(DlpError::InvalidWhitelistProgramConfig.into());
91110
}
@@ -137,20 +156,6 @@ pub fn process_commit_state(
137156
let mut commit_record_data = commit_record_account.try_borrow_mut_data()?;
138157
commit_record.to_bytes_with_discriminator(&mut commit_record_data)?;
139158

140-
// Read undelegation metadata
141-
let mut delegation_metadata_data = delegation_metadata_account.try_borrow_mut_data()?;
142-
let mut delegation_metadata =
143-
DelegationMetadata::try_from_bytes_with_discriminator(&delegation_metadata_data)?;
144-
145-
// Once the account is marked as undelegatable, any subsequent commit should fail
146-
if delegation_metadata.is_undelegatable {
147-
return Err(DlpError::AlreadyUndelegated.into());
148-
}
149-
150-
// Update delegation metadata undelegation flag
151-
delegation_metadata.is_undelegatable = args.allow_undelegation;
152-
delegation_metadata.to_bytes_with_discriminator(&mut delegation_metadata_data.as_mut())?;
153-
154159
// Copy the new state to the initialized PDA
155160
let mut commit_state_data = commit_state_account.try_borrow_mut_data()?;
156161
(*commit_state_data).copy_from_slice(commit_state_bytes);

src/processor/finalize.rs

Lines changed: 44 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use solana_program::{
1919
/// 3. Close the state diff account
2020
/// 4. Close the commit state record
2121
///
22-
///
2322
/// Accounts expected: Authority Record, Buffer PDA, Delegated PDA
2423
pub fn process_finalize(
2524
_program_id: &Pubkey,
@@ -46,64 +45,57 @@ pub fn process_finalize(
4645
let mut delegation_metadata =
4746
DelegationMetadata::try_from_bytes_with_discriminator(&delegation_metadata_data)?;
4847

49-
// Load committed state
48+
// Load delegation record
49+
let mut delegation_record_data = delegation_record_account.try_borrow_mut_data()?;
50+
let delegation_record =
51+
DelegationRecord::try_from_bytes_with_discriminator_mut(&mut delegation_record_data)?;
52+
53+
// Load commit record
5054
let commit_record_data = commit_record_account.try_borrow_data()?;
5155
let commit_record = CommitRecord::try_from_bytes_with_discriminator(&commit_record_data)?;
5256

53-
// If the commit slot is greater than the last update slot, we verify and finalize the state
54-
// If slot is equal or less, we simply close the commitment accounts
55-
// TODO - This could probably be done in the commit_state IX
56-
// TODO - since allowing commiting an obsolete state is counter-productive in the first place?
57-
if commit_record.slot > delegation_metadata.last_update_external_slot {
58-
// Load delegation record
59-
let mut delegation_record_data = delegation_record_account.try_borrow_mut_data()?;
60-
let delegation_record =
61-
DelegationRecord::try_from_bytes_with_discriminator_mut(&mut delegation_record_data)?;
62-
63-
// TODO - We'll need to implement state validation
64-
// TODO - fix: this logic should probably be done in either commit_state OR finalize IX, not both
65-
verify_state(
66-
validator,
67-
delegation_record,
68-
commit_record,
69-
commit_state_account,
70-
)?;
71-
72-
// Check that the commit record is the right now
73-
if !commit_record.account.eq(delegated_account.key) {
74-
return Err(DlpError::InvalidDelegatedAccount.into());
75-
}
76-
if !commit_record.identity.eq(validator.key) {
77-
return Err(DlpError::InvalidReimbursementAccount.into());
78-
}
79-
80-
// Settle accounts lamports
81-
settle_lamports_balance(
82-
delegated_account,
83-
commit_state_account,
84-
validator_fees_vault,
85-
delegation_record.lamports,
86-
commit_record.lamports,
87-
)?;
88-
89-
// Copying the new state to the delegated account
90-
let commit_state_data = commit_state_account.try_borrow_data()?;
91-
delegated_account.realloc(commit_state_data.len(), false)?;
92-
let mut delegated_account_data = delegated_account.try_borrow_mut_data()?;
93-
(*delegated_account_data).copy_from_slice(&commit_state_data);
94-
95-
delegation_metadata.last_update_external_slot = commit_record.slot;
96-
delegation_record.lamports = delegated_account.lamports();
97-
delegation_metadata.to_bytes_with_discriminator(&mut delegation_metadata_data.as_mut())?;
98-
99-
// Dropping references
100-
drop(commit_state_data);
101-
drop(delegated_account_data);
57+
verify_state(
58+
validator,
59+
delegation_record,
60+
commit_record,
61+
commit_state_account,
62+
)?;
63+
64+
// Check that the commit record is the right one
65+
if !commit_record.account.eq(delegated_account.key) {
66+
return Err(DlpError::InvalidDelegatedAccount.into());
10267
}
68+
if !commit_record.identity.eq(validator.key) {
69+
return Err(DlpError::InvalidReimbursementAccount.into());
70+
}
71+
72+
// Settle accounts lamports
73+
settle_lamports_balance(
74+
delegated_account,
75+
commit_state_account,
76+
validator_fees_vault,
77+
delegation_record.lamports,
78+
commit_record.lamports,
79+
)?;
80+
81+
// Update the delegation metadata
82+
delegation_metadata.last_update_external_slot = commit_record.slot;
83+
delegation_metadata.to_bytes_with_discriminator(&mut delegation_metadata_data.as_mut())?;
84+
85+
// Update the delegation record
86+
delegation_record.lamports = delegated_account.lamports();
87+
88+
// Load commit state
89+
let commit_state_data = commit_state_account.try_borrow_data()?;
90+
91+
// Copying the new commit state to the delegated account
92+
delegated_account.realloc(commit_state_data.len(), false)?;
93+
let mut delegated_account_data = delegated_account.try_borrow_mut_data()?;
94+
(*delegated_account_data).copy_from_slice(&commit_state_data);
10395

10496
// Drop remaining reference before closing accounts
10597
drop(commit_record_data);
106-
drop(delegation_metadata_data);
98+
drop(commit_state_data);
10799

108100
// Closing accounts
109101
close_pda(commit_state_account, validator)?;

0 commit comments

Comments
 (0)