This commit is contained in:
anatoly yakovenko 2018-09-09 07:07:38 -07:00 committed by GitHub
parent ebcac3c2d1
commit a89b611e9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 17 deletions

View File

@ -63,7 +63,7 @@ pub enum BankError {
LedgerVerificationFailed, LedgerVerificationFailed,
/// Contract's transaction token balance does not equal the balance after the transaction /// Contract's transaction token balance does not equal the balance after the transaction
UnbalancedTransaction(Signature), UnbalancedTransaction(Signature),
/// ContractAlreadyPending /// Contract location Pubkey already contains userdata
ContractAlreadyPending(Pubkey), ContractAlreadyPending(Pubkey),
} }
@ -232,16 +232,19 @@ impl Bank {
last_ids.push_back(*last_id); last_ids.push_back(*last_id);
} }
/// Deduct tokens from the 'from' address the account has sufficient /// Deduct tokens from the source account if it has sufficient funds and the contract isn't
/// funds and isn't a duplicate. /// pending
fn apply_debits( fn apply_debits_to_budget_payment_plan(
tx: &Transaction, tx: &Transaction,
accounts: &mut [Account], accounts: &mut [Account],
instruction: &Instruction, instruction: &Instruction,
) -> Result<()> { ) -> Result<()> {
{ {
let empty = accounts[0].userdata.is_empty(); let tokens = if !accounts[0].userdata.is_empty() {
let tokens = if !empty { 0 } else { accounts[0].tokens }; 0
} else {
accounts[0].tokens
};
if let Instruction::NewContract(contract) = &instruction { if let Instruction::NewContract(contract) = &instruction {
if contract.tokens < 0 { if contract.tokens < 0 {
return Err(BankError::NegativeTokens); return Err(BankError::NegativeTokens);
@ -260,7 +263,7 @@ impl Bank {
/// Apply only a transaction's credits. /// Apply only a transaction's credits.
/// Note: It is safe to apply credits from multiple transactions in parallel. /// Note: It is safe to apply credits from multiple transactions in parallel.
fn apply_credits( fn apply_credits_to_budget_payment_plan(
tx: &Transaction, tx: &Transaction,
accounts: &mut [Account], accounts: &mut [Account],
instruction: &Instruction, instruction: &Instruction,
@ -276,7 +279,7 @@ impl Bank {
} else { } else {
let mut pending = HashMap::new(); let mut pending = HashMap::new();
pending.insert(tx.signature, plan); pending.insert(tx.signature, plan);
//TODO this is a temporary on demand allocaiton //TODO this is a temporary on demand allocation
//until system contract requires explicit allocation of memory //until system contract requires explicit allocation of memory
accounts[1].userdata = serialize(&pending).unwrap(); accounts[1].userdata = serialize(&pending).unwrap();
accounts[1].tokens += contract.tokens; accounts[1].tokens += contract.tokens;
@ -308,8 +311,8 @@ impl Bank {
accounts: &mut [Account], accounts: &mut [Account],
) -> Result<()> { ) -> Result<()> {
let instruction = tx.instruction(); let instruction = tx.instruction();
Self::apply_debits(tx, accounts, &instruction)?; Self::apply_debits_to_budget_payment_plan(tx, accounts, &instruction)?;
Self::apply_credits(tx, accounts, &instruction) Self::apply_credits_to_budget_payment_plan(tx, accounts, &instruction)
} }
//TODO the contract needs to provide a "get_balance" introspection call of the userdata //TODO the contract needs to provide a "get_balance" introspection call of the userdata
pub fn get_balance_of_budget_payment_plan(account: &Account) -> i64 { pub fn get_balance_of_budget_payment_plan(account: &Account) -> i64 {
@ -918,7 +921,7 @@ mod tests {
// pubkey's balance will be 0 because the funds are locked up // pubkey's balance will be 0 because the funds are locked up
assert_eq!(bank.get_balance(&pubkey), 0); assert_eq!(bank.get_balance(&pubkey), 0);
// Now, cancel the trancaction. Mint gets her funds back, pubkey never sees them. // Now, cancel the transaction. Mint gets her funds back, pubkey never sees them.
let tx = Transaction::new_signature(&mint.keypair(), pubkey, signature, bank.last_id()); let tx = Transaction::new_signature(&mint.keypair(), pubkey, signature, bank.last_id());
let res = bank.process_transaction(&tx); let res = bank.process_transaction(&tx);
assert!(res.is_ok()); assert!(res.is_ok());

View File

@ -188,8 +188,8 @@ impl ThinClient {
self.process_response(&resp); self.process_response(&resp);
} }
trace!("get_balance {:?}", self.balances.get(pubkey)); trace!("get_balance {:?}", self.balances.get(pubkey));
//TODO: call the contract specific get_balance for contract_id's thin client can introspect // TODO: This is a hard coded call to introspect the balance of a budget_dsl contract
//instead of hard coding to budget_dsl only // In the future custom contracts would need their own introspection
self.balances self.balances
.get(pubkey) .get(pubkey)
.map(Bank::get_balance_of_budget_payment_plan) .map(Bank::get_balance_of_budget_payment_plan)

View File

@ -84,9 +84,9 @@ pub struct Transaction {
/// The `Pubkeys` that are executing this transaction userdata. The meaning of each key is /// The `Pubkeys` that are executing this transaction userdata. The meaning of each key is
/// contract-specific. /// contract-specific.
/// * keys[0] - Typically this is the `from` public key. `signature` is verified with keys[0]. /// * keys[0] - Typically this is the `caller` public key. `signature` is verified with keys[0].
/// In the future which key pays the fee and which keys have signatures would be configurable. /// In the future which key pays the fee and which keys have signatures would be configurable.
/// * keys[1] - Typically this is the contract context or the recepient of the tokens /// * keys[1] - Typically this is the contract context or the recipient of the tokens
pub keys: Vec<Pubkey>, pub keys: Vec<Pubkey>,
/// The ID of a recent ledger entry. /// The ID of a recent ledger entry.
@ -103,7 +103,7 @@ impl Transaction {
/// Create a signed transaction from the given `Instruction`. /// Create a signed transaction from the given `Instruction`.
/// * `from_keypair` - The key used to sign the transcation. This key is stored as keys[0] /// * `from_keypair` - The key used to sign the transcation. This key is stored as keys[0]
/// * `transaction_keys` - The keys for the transaction. These are the contract state /// * `transaction_keys` - The keys for the transaction. These are the contract state
/// instances or token recepient keys. /// instances or token recipient keys.
/// * `userdata` - The input data that the contract will execute with /// * `userdata` - The input data that the contract will execute with
/// * `last_id` - The PoH hash. /// * `last_id` - The PoH hash.
/// * `fee` - The transaction fee. /// * `fee` - The transaction fee.
@ -135,7 +135,7 @@ impl Transaction {
last_id: Hash, last_id: Hash,
fee: i64, fee: i64,
) -> Self { ) -> Self {
let userdata = serialize(&instruction).expect("serealize instruction"); let userdata = serialize(&instruction).unwrap();
Self::new_with_userdata(from_keypair, &[contract], userdata, last_id, fee) Self::new_with_userdata(from_keypair, &[contract], userdata, last_id, fee)
} }