Slimmer implementation of credit-only accounts (#4592)
* Add credit-only debit/data check to verify_instruction * Store credits and pass to accounts_db * Add InstructionErrors and tests * Relax account locks for credit-only accounts * Collect credit-only account credits before passing to accounts_db to store properly * Convert System Transfer accounts to credit-only, and fixup test * Functionalize collect_accounts to unit test * Review comments * Rebase
This commit is contained in:
@ -55,6 +55,8 @@ impl Account {
|
||||
}
|
||||
}
|
||||
|
||||
pub type LamportCredit = u64;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct KeyedAccount<'a> {
|
||||
|
@ -52,6 +52,12 @@ pub enum InstructionError {
|
||||
/// Program modified the data of an account that doesn't belong to it
|
||||
ExternalAccountDataModified,
|
||||
|
||||
/// Credit-only account spent lamports
|
||||
CreditOnlyLamportSpend,
|
||||
|
||||
/// Credit-only account modified data
|
||||
CreditOnlyDataModified,
|
||||
|
||||
/// An account was referenced more than once in a single instruction
|
||||
DuplicateAccountIndex,
|
||||
|
||||
|
@ -216,7 +216,7 @@ impl Message {
|
||||
.position(|&&pubkey| pubkey == self.account_keys[index])
|
||||
}
|
||||
|
||||
fn is_credit_debit(&self, i: usize) -> bool {
|
||||
pub fn is_debitable(&self, i: usize) -> bool {
|
||||
i < (self.header.num_required_signatures - self.header.num_credit_only_signed_accounts)
|
||||
as usize
|
||||
|| (i >= self.header.num_required_signatures as usize
|
||||
@ -228,7 +228,7 @@ impl Message {
|
||||
let mut credit_debit_keys = vec![];
|
||||
let mut credit_only_keys = vec![];
|
||||
for (i, key) in self.account_keys.iter().enumerate() {
|
||||
if self.is_credit_debit(i) {
|
||||
if self.is_debitable(i) {
|
||||
credit_debit_keys.push(key);
|
||||
} else {
|
||||
credit_only_keys.push(key);
|
||||
@ -516,7 +516,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_credit_debit() {
|
||||
fn test_is_debitable() {
|
||||
let key0 = Pubkey::new_rand();
|
||||
let key1 = Pubkey::new_rand();
|
||||
let key2 = Pubkey::new_rand();
|
||||
@ -534,12 +534,12 @@ mod tests {
|
||||
recent_blockhash: Hash::default(),
|
||||
instructions: vec![],
|
||||
};
|
||||
assert_eq!(message.is_credit_debit(0), true);
|
||||
assert_eq!(message.is_credit_debit(1), false);
|
||||
assert_eq!(message.is_credit_debit(2), false);
|
||||
assert_eq!(message.is_credit_debit(3), true);
|
||||
assert_eq!(message.is_credit_debit(4), true);
|
||||
assert_eq!(message.is_credit_debit(5), false);
|
||||
assert_eq!(message.is_debitable(0), true);
|
||||
assert_eq!(message.is_debitable(1), false);
|
||||
assert_eq!(message.is_debitable(2), false);
|
||||
assert_eq!(message.is_debitable(3), true);
|
||||
assert_eq!(message.is_debitable(4), true);
|
||||
assert_eq!(message.is_debitable(5), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -90,7 +90,7 @@ pub fn assign(from_pubkey: &Pubkey, program_id: &Pubkey) -> Instruction {
|
||||
pub fn transfer(from_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction {
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*from_pubkey, true),
|
||||
AccountMeta::new(*to_pubkey, false),
|
||||
AccountMeta::new_credit_only(*to_pubkey, false),
|
||||
];
|
||||
Instruction::new(
|
||||
system_program::id(),
|
||||
|
Reference in New Issue
Block a user