budget as separate contract and system call contract (#1189)

* budget and system contracts and verification

* contract check_id methods
* system call contract
* verify contract execution rules
* move system into its own file
* allocate before transfer for budget
* store error in budget context
* budget contract and tests without bank
* moved budget of of bank
This commit is contained in:
anatoly yakovenko
2018-09-17 13:36:31 -07:00
committed by GitHub
parent 072b244575
commit 6ec0e42220
15 changed files with 951 additions and 450 deletions

80
src/system_contract.rs Normal file
View File

@@ -0,0 +1,80 @@
//! system smart contract
use bank::Account;
use bincode::deserialize;
use signature::Pubkey;
use transaction::Transaction;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum SystemContract {
/// Create a new account
/// * Transaction::keys[0] - source
/// * Transaction::keys[1] - new account key
/// * tokens - number of tokens to transfer to the new account
/// * space - memory to allocate if greater then zero
/// * contract - the contract id of the new account
CreateAccount {
tokens: i64,
space: u64,
contract_id: Option<Pubkey>,
},
/// Assign account to a contract
/// * Transaction::keys[0] - account to assign
Assign { contract_id: Pubkey },
/// Move tokens
/// * Transaction::keys[0] - source
/// * Transaction::keys[1] - destination
Move { tokens: i64 },
}
pub const SYSTEM_CONTRACT_ID: [u8; 32] = [0u8; 32];
impl SystemContract {
pub fn check_id(contract_id: &Pubkey) -> bool {
contract_id.as_ref() == SYSTEM_CONTRACT_ID
}
pub fn id() -> Pubkey {
Pubkey::new(&SYSTEM_CONTRACT_ID)
}
pub fn get_balance(account: &Account) -> i64 {
account.tokens
}
pub fn process_transaction(tx: &Transaction, accounts: &mut [Account]) {
let syscall: SystemContract = deserialize(&tx.userdata).unwrap();
match syscall {
SystemContract::CreateAccount {
tokens,
space,
contract_id,
} => {
if !Self::check_id(&accounts[1].contract_id) {
return;
}
if !Self::check_id(&accounts[0].contract_id) {
return;
}
if space > 0 && !accounts[1].userdata.is_empty() {
return;
}
accounts[0].tokens -= tokens;
accounts[1].tokens += tokens;
if let Some(id) = contract_id {
accounts[1].contract_id = id;
}
accounts[1].userdata = vec![0; space as usize];
}
SystemContract::Assign { contract_id } => {
if !Self::check_id(&accounts[0].contract_id) {
return;
}
accounts[0].contract_id = contract_id;
}
SystemContract::Move { tokens } => {
//bank should be verifying correctness
accounts[0].tokens -= tokens;
accounts[1].tokens += tokens;
}
}
}
}