Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Commit

Permalink
Integration of native dynamic programs
Browse files Browse the repository at this point in the history
  • Loading branch information
jackcmay committed Sep 21, 2018
1 parent 2614189 commit f002faf
Show file tree
Hide file tree
Showing 12 changed files with 495 additions and 14 deletions.
23 changes: 22 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc", rev = "4b
jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc", rev = "4b6060b" }
ipnetwork = "0.12.7"
itertools = "0.7.8"
libc = "0.2.43"
libloading = "0.5.0"
log = "0.4.2"
matches = "0.1.6"
nix = "0.11.0"
Expand All @@ -102,7 +104,11 @@ sys-info = "0.5.6"
tokio = "0.1"
tokio-codec = "0.1"
untrusted = "0.6.2"
libc = "0.2.43"

[dev-dependencies]
noop = { path = "programs/noop" }
print = { path = "programs/print" }
move_funds = { path = "programs/move_funds" }

[[bench]]
name = "bank"
Expand All @@ -118,3 +124,18 @@ name = "signature"

[[bench]]
name = "sigverify"

[workspace]
members = [
".",
"programs/noop",
"programs/print",
"programs/move_funds",
]
default-members = [
".",
"programs/noop",
"programs/print",
"programs/move_funds",
]

24 changes: 24 additions & 0 deletions programs/move_funds/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "move_funds"
version = "0.1.0"
authors = [
"Anatoly Yakovenko <anatoly@solana.com>",
"Greg Fitzgerald <greg@solana.com>",
"Stephen Akridge <stephen@solana.com>",
"Michael Vines <mvines@solana.com>",
"Rob Walker <rob@solana.com>",
"Pankaj Garg <pankaj@solana.com>",
"Tyera Eulberg <tyera@solana.com>",
"Jack May <jack@solana.com>",
]

[dependencies]
bincode = "1.0.0"
generic-array = { version = "0.12.0", default-features = false, features = ["serde"] }
libloading = "0.5.0"
solana = { path = "../.." }

[lib]
name = "move_funds"
crate-type = ["dylib"]

48 changes: 48 additions & 0 deletions programs/move_funds/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
extern crate bincode;
extern crate solana;

use bincode::deserialize;
use solana::dynamic_program::KeyedAccount;

#[no_mangle]
pub extern "C" fn process(infos: &mut Vec<KeyedAccount>, data: &[u8]) {
let tokens: i64 = deserialize(data).unwrap();
if infos[0].account.tokens >= tokens {
infos[0].account.tokens -= tokens;
infos[1].account.tokens += tokens;
} else {
println!(
"Insufficient funds, asked {}, only had {}",
tokens, infos[0].account.tokens
);
}
}

#[cfg(test)]
mod tests {
use super::*;
use bincode::serialize;
use solana::bank::Account;
use solana::signature::Pubkey;

#[test]
fn test_move_funds() {
let tokens: i64 = 100;
let data: Vec<u8> = serialize(&tokens).unwrap();
let keys = vec![Pubkey::default(); 2];
let mut accounts = vec![Account::default(), Account::default()];
accounts[0].tokens = 100;
accounts[1].tokens = 1;

{
let mut infos: Vec<KeyedAccount> = Vec::new();
for (key, account) in keys.iter().zip(&mut accounts).collect::<Vec<_>>() {
infos.push(KeyedAccount { key, account });
}

process(&mut infos, &data);
}
assert_eq!(0, accounts[0].tokens);
assert_eq!(101, accounts[1].tokens);
}
}
22 changes: 22 additions & 0 deletions programs/noop/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "noop"
version = "0.1.0"
authors = [
"Anatoly Yakovenko <anatoly@solana.com>",
"Greg Fitzgerald <greg@solana.com>",
"Stephen Akridge <stephen@solana.com>",
"Michael Vines <mvines@solana.com>",
"Rob Walker <rob@solana.com>",
"Pankaj Garg <pankaj@solana.com>",
"Tyera Eulberg <tyera@solana.com>",
"Jack May <jack@solana.com>",
]

[dependencies]
libloading = "0.5.0"
solana = { path = "../.." }

[lib]
name = "noop"
crate-type = ["dylib"]

6 changes: 6 additions & 0 deletions programs/noop/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extern crate solana;

use solana::dynamic_program::KeyedAccount;

#[no_mangle]
pub extern "C" fn process(_infos: &mut Vec<KeyedAccount>, _data: &[u8]) {}
22 changes: 22 additions & 0 deletions programs/print/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "print"
version = "0.1.0"
authors = [
"Anatoly Yakovenko <anatoly@solana.com>",
"Greg Fitzgerald <greg@solana.com>",
"Stephen Akridge <stephen@solana.com>",
"Michael Vines <mvines@solana.com>",
"Rob Walker <rob@solana.com>",
"Pankaj Garg <pankaj@solana.com>",
"Tyera Eulberg <tyera@solana.com>",
"Jack May <jack@solana.com>",
]

[dependencies]
libloading = "0.5.0"
solana = { path = "../.." }

[lib]
name = "print"
crate-type = ["dylib"]

9 changes: 9 additions & 0 deletions programs/print/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
extern crate solana;

use solana::dynamic_program::KeyedAccount;

#[no_mangle]
pub extern "C" fn process(infos: &mut Vec<KeyedAccount>, _data: &[u8]) {
println!("AccountInfos: {:#?}", infos);
//println!("data: {:#?}", data);
}
36 changes: 33 additions & 3 deletions src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use bincode::deserialize;
use bincode::serialize;
use budget_program::BudgetState;
use counter::Counter;
use dynamic_program::{DynamicProgram, KeyedAccount};
use entry::Entry;
use hash::{hash, Hash};
use itertools::Itertools;
Expand Down Expand Up @@ -135,6 +136,9 @@ pub struct Bank {

// The latest finality time for the network
finality_time: AtomicUsize,

// loaded contracts hashed by program_id
loaded_contracts: RwLock<HashMap<Pubkey, DynamicProgram>>,
}

impl Default for Bank {
Expand All @@ -146,6 +150,7 @@ impl Default for Bank {
transaction_count: AtomicUsize::new(0),
is_leader: true,
finality_time: AtomicUsize::new(std::usize::MAX),
loaded_contracts: RwLock::new(HashMap::new()),
}
}
}
Expand Down Expand Up @@ -306,6 +311,7 @@ impl Bank {
Ok(called_accounts)
}
}

fn load_accounts(
&self,
txs: &[Transaction],
Expand All @@ -316,6 +322,7 @@ impl Bank {
.map(|tx| self.load_account(tx, accounts, error_counters))
.collect()
}

pub fn verify_transaction(
tx: &Transaction,
pre_program_id: &Pubkey,
Expand All @@ -340,11 +347,33 @@ impl Bank {
}
Ok(())
}

fn loaded_contract(&self, tx: &Transaction, accounts: &mut [Account]) -> bool {
let loaded_contracts = self.loaded_contracts.write().unwrap();
match loaded_contracts.get(&tx.program_id) {
Some(dc) => {
let mut infos: Vec<_> = (&tx.keys)
.into_iter()
.zip(accounts)
.map(|(key, account)| KeyedAccount { key, account })
.collect();

dc.call(&mut infos, &tx.userdata);
true
}
None => false,
}
}

/// Execute a transaction.
/// This method calls the contract's process_transaction method and verifies that the result of
/// the contract does not violate the bank's accounting rules.
/// The accounts are committed back to the bank only if this function returns Ok(_).
fn execute_transaction(tx: Transaction, accounts: &mut [Account]) -> Result<Transaction> {
fn execute_transaction(
&self,
tx: Transaction,
accounts: &mut [Account],
) -> Result<Transaction> {
let pre_total: i64 = accounts.iter().map(|a| a.tokens).sum();
let pre_data: Vec<_> = accounts
.iter_mut()
Expand All @@ -354,11 +383,12 @@ impl Bank {
// Call the contract method
// It's up to the contract to implement its own rules on moving funds
if SystemProgram::check_id(&tx.program_id) {
SystemProgram::process_transaction(&tx, accounts)
SystemProgram::process_transaction(&tx, accounts, &self.loaded_contracts)
} else if BudgetState::check_id(&tx.program_id) {
// TODO: the runtime should be checking read/write access to memory
// we are trusting the hard coded contracts not to clobber or allocate
BudgetState::process_transaction(&tx, accounts)
} else if self.loaded_contract(&tx, accounts) {
} else {
return Err(BankError::UnknownContractId(tx.program_id));
}
Expand Down Expand Up @@ -415,7 +445,7 @@ impl Bank {
.zip(txs.into_iter())
.map(|(acc, tx)| match acc {
Err(e) => Err(e.clone()),
Ok(ref mut accounts) => Self::execute_transaction(tx, accounts),
Ok(ref mut accounts) => self.execute_transaction(tx, accounts),
}).collect();
let execution_elapsed = now.elapsed();
let now = Instant::now();
Expand Down
Loading

0 comments on commit f002faf

Please sign in to comment.