WritableAccount.add/subtract_lamports (#16750)
* add/sub lamports * make add/sub return Result * sample replacements * cleanup * fix up a few tests as examples * move enum, cleanup, impl from * fmt * cleanup * add lamports.rs
This commit is contained in:
committed by
GitHub
parent
be29568318
commit
48c07d32f0
@ -36,7 +36,9 @@ fn apply_signature(
|
|||||||
if &payment.to == key {
|
if &payment.to == key {
|
||||||
budget_state.pending_budget = None;
|
budget_state.pending_budget = None;
|
||||||
contract_keyed_account.try_account_ref_mut()?.lamports -= payment.lamports;
|
contract_keyed_account.try_account_ref_mut()?.lamports -= payment.lamports;
|
||||||
witness_keyed_account.try_account_ref_mut()?.lamports += payment.lamports;
|
witness_keyed_account
|
||||||
|
.try_account_ref_mut()?
|
||||||
|
.checked_add_lamports(payment.lamports)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6194,7 +6194,7 @@ pub mod tests {
|
|||||||
if let Some((mut account, _)) =
|
if let Some((mut account, _)) =
|
||||||
accounts.load_without_fixed_root(&ancestors, &pubkeys[idx])
|
accounts.load_without_fixed_root(&ancestors, &pubkeys[idx])
|
||||||
{
|
{
|
||||||
account.lamports += 1;
|
account.checked_add_lamports(1).unwrap();
|
||||||
accounts.store_uncached(slot, &[(&pubkeys[idx], &account)]);
|
accounts.store_uncached(slot, &[(&pubkeys[idx], &account)]);
|
||||||
if account.lamports == 0 {
|
if account.lamports == 0 {
|
||||||
let ancestors = vec![(slot, 0)].into_iter().collect();
|
let ancestors = vec![(slot, 0)].into_iter().collect();
|
||||||
|
@ -9870,8 +9870,12 @@ pub(crate) mod tests {
|
|||||||
dup_account.lamports -= lamports;
|
dup_account.lamports -= lamports;
|
||||||
to_account.lamports += lamports;
|
to_account.lamports += lamports;
|
||||||
}
|
}
|
||||||
keyed_accounts[0].try_account_ref_mut()?.lamports -= lamports;
|
keyed_accounts[0]
|
||||||
keyed_accounts[1].try_account_ref_mut()?.lamports += lamports;
|
.try_account_ref_mut()?
|
||||||
|
.checked_sub_lamports(lamports)?;
|
||||||
|
keyed_accounts[1]
|
||||||
|
.try_account_ref_mut()?
|
||||||
|
.checked_add_lamports(lamports)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
sdk/program/src/lamports.rs
Normal file
22
sdk/program/src/lamports.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use crate::instruction::InstructionError;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum LamportsError {
|
||||||
|
/// arithmetic underflowed
|
||||||
|
#[error("Arithmetic underflowed")]
|
||||||
|
ArithmeticUnderflow,
|
||||||
|
|
||||||
|
/// arithmetic overflowed
|
||||||
|
#[error("Arithmetic overflowed")]
|
||||||
|
ArithmeticOverflow,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LamportsError> for InstructionError {
|
||||||
|
fn from(error: LamportsError) -> Self {
|
||||||
|
match error {
|
||||||
|
LamportsError::ArithmeticOverflow => InstructionError::ArithmeticOverflow,
|
||||||
|
LamportsError::ArithmeticUnderflow => InstructionError::ArithmeticOverflow,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,7 @@ pub mod fee_calculator;
|
|||||||
pub mod hash;
|
pub mod hash;
|
||||||
pub mod incinerator;
|
pub mod incinerator;
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
|
pub mod lamports;
|
||||||
pub mod loader_instruction;
|
pub mod loader_instruction;
|
||||||
pub mod loader_upgradeable_instruction;
|
pub mod loader_upgradeable_instruction;
|
||||||
pub mod log;
|
pub mod log;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
clock::{Epoch, INITIAL_RENT_EPOCH},
|
clock::{Epoch, INITIAL_RENT_EPOCH},
|
||||||
|
lamports::LamportsError,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
use solana_program::{account_info::AccountInfo, sysvar::Sysvar};
|
use solana_program::{account_info::AccountInfo, sysvar::Sysvar};
|
||||||
@ -79,6 +80,22 @@ impl From<Account> for AccountSharedData {
|
|||||||
|
|
||||||
pub trait WritableAccount: ReadableAccount {
|
pub trait WritableAccount: ReadableAccount {
|
||||||
fn set_lamports(&mut self, lamports: u64);
|
fn set_lamports(&mut self, lamports: u64);
|
||||||
|
fn checked_add_lamports(&mut self, lamports: u64) -> Result<(), LamportsError> {
|
||||||
|
self.set_lamports(
|
||||||
|
self.lamports()
|
||||||
|
.checked_add(lamports)
|
||||||
|
.ok_or(LamportsError::ArithmeticOverflow)?,
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn checked_sub_lamports(&mut self, lamports: u64) -> Result<(), LamportsError> {
|
||||||
|
self.set_lamports(
|
||||||
|
self.lamports()
|
||||||
|
.checked_sub(lamports)
|
||||||
|
.ok_or(LamportsError::ArithmeticUnderflow)?,
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
fn data_as_mut_slice(&mut self) -> &mut [u8];
|
fn data_as_mut_slice(&mut self) -> &mut [u8];
|
||||||
fn set_owner(&mut self, owner: Pubkey);
|
fn set_owner(&mut self, owner: Pubkey);
|
||||||
fn copy_into_owner_from_slice(&mut self, source: &[u8]);
|
fn copy_into_owner_from_slice(&mut self, source: &[u8]);
|
||||||
@ -709,6 +726,53 @@ pub mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_account_add_sub_lamports() {
|
||||||
|
let key = Pubkey::new_unique();
|
||||||
|
let (mut account1, mut account2) = make_two_accounts(&key);
|
||||||
|
assert!(accounts_equal(&account1, &account2));
|
||||||
|
account1.checked_add_lamports(1).unwrap();
|
||||||
|
account2.checked_add_lamports(1).unwrap();
|
||||||
|
assert!(accounts_equal(&account1, &account2));
|
||||||
|
assert_eq!(account1.lamports(), 2);
|
||||||
|
account1.checked_sub_lamports(2).unwrap();
|
||||||
|
account2.checked_sub_lamports(2).unwrap();
|
||||||
|
assert!(accounts_equal(&account1, &account2));
|
||||||
|
assert_eq!(account1.lamports(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Overflow")]
|
||||||
|
fn test_account_checked_add_lamports_overflow() {
|
||||||
|
let key = Pubkey::new_unique();
|
||||||
|
let (mut account1, _account2) = make_two_accounts(&key);
|
||||||
|
account1.checked_add_lamports(u64::MAX).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Underflow")]
|
||||||
|
fn test_account_checked_sub_lamports_underflow() {
|
||||||
|
let key = Pubkey::new_unique();
|
||||||
|
let (mut account1, _account2) = make_two_accounts(&key);
|
||||||
|
account1.checked_sub_lamports(u64::MAX).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Overflow")]
|
||||||
|
fn test_account_checked_add_lamports_overflow2() {
|
||||||
|
let key = Pubkey::new_unique();
|
||||||
|
let (_account1, mut account2) = make_two_accounts(&key);
|
||||||
|
account2.checked_add_lamports(u64::MAX).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Underflow")]
|
||||||
|
fn test_account_checked_sub_lamports_underflow2() {
|
||||||
|
let key = Pubkey::new_unique();
|
||||||
|
let (_account1, mut account2) = make_two_accounts(&key);
|
||||||
|
account2.checked_sub_lamports(u64::MAX).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(clippy::redundant_clone)]
|
#[allow(clippy::redundant_clone)]
|
||||||
fn test_account_shared_data_all_fields() {
|
fn test_account_shared_data_all_fields() {
|
||||||
@ -726,15 +790,15 @@ pub mod tests {
|
|||||||
for pass in 0..4 {
|
for pass in 0..4 {
|
||||||
if field_index == 0 {
|
if field_index == 0 {
|
||||||
if pass == 0 {
|
if pass == 0 {
|
||||||
account1.lamports += 1;
|
account1.checked_add_lamports(1).unwrap();
|
||||||
} else if pass == 1 {
|
} else if pass == 1 {
|
||||||
account_expected.lamports += 1;
|
account_expected.checked_add_lamports(1).unwrap();
|
||||||
account2.set_lamports(account2.lamports + 1);
|
account2.set_lamports(account2.lamports + 1);
|
||||||
} else if pass == 2 {
|
} else if pass == 2 {
|
||||||
account1.set_lamports(account1.lamports + 1);
|
account1.set_lamports(account1.lamports + 1);
|
||||||
} else if pass == 3 {
|
} else if pass == 3 {
|
||||||
account_expected.lamports += 1;
|
account_expected.checked_add_lamports(1).unwrap();
|
||||||
account2.lamports += 1;
|
account2.checked_add_lamports(1).unwrap();
|
||||||
}
|
}
|
||||||
} else if field_index == 1 {
|
} else if field_index == 1 {
|
||||||
if pass == 0 {
|
if pass == 0 {
|
||||||
|
Reference in New Issue
Block a user