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:
Tyera Eulberg
2019-06-10 20:50:02 -06:00
committed by GitHub
parent 9259d342ac
commit 807c69d97c
11 changed files with 474 additions and 127 deletions

View File

@ -55,6 +55,8 @@ impl Account {
}
}
pub type LamportCredit = u64;
#[repr(C)]
#[derive(Debug)]
pub struct KeyedAccount<'a> {

View File

@ -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,

View File

@ -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]

View File

@ -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(),