Move budget_program out of src/

This commit is contained in:
Michael Vines 2018-12-04 14:38:19 -08:00
parent 27d456bf93
commit 9ee858a00c
20 changed files with 212 additions and 220 deletions

16
Cargo.lock generated
View File

@ -1762,6 +1762,7 @@ dependencies = [
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-bpfloader 0.11.0", "solana-bpfloader 0.11.0",
"solana-budget-program 0.11.0",
"solana-drone 0.11.0", "solana-drone 0.11.0",
"solana-erc20 0.11.0", "solana-erc20 0.11.0",
"solana-jsonrpc-core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "solana-jsonrpc-core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1806,6 +1807,19 @@ dependencies = [
"solana_rbpf 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "solana_rbpf 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "solana-budget-program"
version = "0.11.0"
dependencies = [
"bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-sdk 0.11.0",
]
[[package]] [[package]]
name = "solana-drone" name = "solana-drone"
version = "0.11.0" version = "0.11.0"
@ -1949,6 +1963,7 @@ dependencies = [
"bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1987,6 +2002,7 @@ name = "solana-vote-program"
version = "0.11.0" version = "0.11.0"
dependencies = [ dependencies = [
"bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -98,6 +98,7 @@ serde_json = "1.0.10"
sha2 = "0.8.0" sha2 = "0.8.0"
socket2 = "0.3.8" socket2 = "0.3.8"
solana-bpfloader = { path = "programs/native/bpf_loader", version = "0.11.0" } solana-bpfloader = { path = "programs/native/bpf_loader", version = "0.11.0" }
solana-budget-program = { path = "programs/native/budget", version = "0.11.0" }
solana-drone = { path = "drone", version = "0.11.0" } solana-drone = { path = "drone", version = "0.11.0" }
solana-erc20 = { path = "programs/native/erc20", version = "0.11.0" } solana-erc20 = { path = "programs/native/erc20", version = "0.11.0" }
solana-jsonrpc-core = "0.3.0" solana-jsonrpc-core = "0.3.0"
@ -148,6 +149,7 @@ members = [
"sdk", "sdk",
"programs/bpf/rust/noop", "programs/bpf/rust/noop",
"programs/native/bpf_loader", "programs/native/bpf_loader",
"programs/native/budget",
"programs/native/erc20", "programs/native/erc20",
"programs/native/lua_loader", "programs/native/lua_loader",
"programs/native/noop", "programs/native/noop",

View File

@ -0,0 +1,21 @@
[package]
name = "solana-budget-program"
version = "0.11.0"
description = "Solana budget program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
[dependencies]
bincode = "1.0.0"
chrono = { version = "0.4.0", features = ["serde"] }
env_logger = "0.6.0"
log = "0.4.2"
serde = "1.0.27"
serde_derive = "1.0.27"
solana-sdk = { path = "../../../sdk", version = "0.11.0" }
[lib]
name = "solana_budget_program"
crate-type = ["cdylib"]

View File

@ -1,13 +1,10 @@
//! budget program //! budget program
use bincode::{self, deserialize, serialize_into, serialized_size}; use bincode::{self, deserialize, serialize_into, serialized_size};
use budget_expr::BudgetExpr;
use budget_instruction::Instruction;
use chrono::prelude::{DateTime, Utc}; use chrono::prelude::{DateTime, Utc};
use payment_plan::Witness; use solana_sdk::account::KeyedAccount;
use solana_sdk::account::Account; use solana_sdk::budget_expr::BudgetExpr;
use solana_sdk::native_program::ProgramError; use solana_sdk::budget_instruction::Instruction;
use solana_sdk::pubkey::Pubkey; use solana_sdk::payment_plan::Witness;
use solana_sdk::transaction::Transaction;
use std::io; use std::io;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
@ -31,26 +28,11 @@ pub struct BudgetProgram {
pub pending_budget: Option<BudgetExpr>, pub pending_budget: Option<BudgetExpr>,
} }
const BUDGET_PROGRAM_ID: [u8; 32] = [
129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
];
pub fn id() -> Pubkey {
Pubkey::new(&BUDGET_PROGRAM_ID)
}
pub fn check_id(program_id: &Pubkey) -> bool {
program_id.as_ref() == BUDGET_PROGRAM_ID
}
fn apply_debits( fn apply_debits(
tx: &Transaction, keyed_accounts: &mut [KeyedAccount],
instruction_index: usize,
accounts: &mut [&mut Account],
instruction: &Instruction, instruction: &Instruction,
) -> Result<(), BudgetError> { ) -> Result<(), BudgetError> {
if !accounts[0].userdata.is_empty() { if !keyed_accounts[0].account.userdata.is_empty() {
trace!("source is pending"); trace!("source is pending");
return Err(BudgetError::SourceIsPendingContract); return Err(BudgetError::SourceIsPendingContract);
} }
@ -58,25 +40,26 @@ fn apply_debits(
Instruction::NewBudget(expr) => { Instruction::NewBudget(expr) => {
let expr = expr.clone(); let expr = expr.clone();
if let Some(payment) = expr.final_payment() { if let Some(payment) = expr.final_payment() {
accounts[1].tokens += payment.tokens; keyed_accounts[1].account.tokens += payment.tokens;
Ok(()) Ok(())
} else { } else {
let existing = BudgetProgram::deserialize(&accounts[1].userdata).ok(); let existing = BudgetProgram::deserialize(&keyed_accounts[1].account.userdata).ok();
if Some(true) == existing.map(|x| x.initialized) { if Some(true) == existing.map(|x| x.initialized) {
trace!("contract already exists"); trace!("contract already exists");
Err(BudgetError::ContractAlreadyExists) Err(BudgetError::ContractAlreadyExists)
} else { } else {
let mut program = BudgetProgram::default(); let mut program = BudgetProgram::default();
program.pending_budget = Some(expr); program.pending_budget = Some(expr);
accounts[1].tokens += accounts[0].tokens; keyed_accounts[1].account.tokens += keyed_accounts[0].account.tokens;
accounts[0].tokens = 0; keyed_accounts[0].account.tokens = 0;
program.initialized = true; program.initialized = true;
program.serialize(&mut accounts[1].userdata) program.serialize(&mut keyed_accounts[1].account.userdata)
} }
} }
} }
Instruction::ApplyTimestamp(dt) => { Instruction::ApplyTimestamp(dt) => {
if let Ok(mut program) = BudgetProgram::deserialize(&accounts[1].userdata) { if let Ok(mut program) = BudgetProgram::deserialize(&keyed_accounts[1].account.userdata)
{
if !program.is_pending() { if !program.is_pending() {
Err(BudgetError::ContractNotPending) Err(BudgetError::ContractNotPending)
} else if !program.initialized { } else if !program.initialized {
@ -84,16 +67,17 @@ fn apply_debits(
Err(BudgetError::UninitializedContract) Err(BudgetError::UninitializedContract)
} else { } else {
trace!("apply timestamp"); trace!("apply timestamp");
program.apply_timestamp(tx, instruction_index, accounts, *dt)?; program.apply_timestamp(keyed_accounts, *dt)?;
trace!("apply timestamp committed"); trace!("apply timestamp committed");
program.serialize(&mut accounts[1].userdata) program.serialize(&mut keyed_accounts[1].account.userdata)
} }
} else { } else {
Err(BudgetError::UninitializedContract) Err(BudgetError::UninitializedContract)
} }
} }
Instruction::ApplySignature => { Instruction::ApplySignature => {
if let Ok(mut program) = BudgetProgram::deserialize(&accounts[1].userdata) { if let Ok(mut program) = BudgetProgram::deserialize(&keyed_accounts[1].account.userdata)
{
if !program.is_pending() { if !program.is_pending() {
Err(BudgetError::ContractNotPending) Err(BudgetError::ContractNotPending)
} else if !program.initialized { } else if !program.initialized {
@ -101,9 +85,9 @@ fn apply_debits(
Err(BudgetError::UninitializedContract) Err(BudgetError::UninitializedContract)
} else { } else {
trace!("apply signature"); trace!("apply signature");
program.apply_signature(tx, instruction_index, accounts)?; program.apply_signature(keyed_accounts)?;
trace!("apply signature committed"); trace!("apply signature committed");
program.serialize(&mut accounts[1].userdata) program.serialize(&mut keyed_accounts[1].account.userdata)
} }
} else { } else {
Err(BudgetError::UninitializedContract) Err(BudgetError::UninitializedContract)
@ -113,36 +97,24 @@ fn apply_debits(
} }
/// Budget DSL contract interface /// Budget DSL contract interface
/// * tx - the transaction
/// * accounts[0] - The source of the tokens /// * accounts[0] - The source of the tokens
/// * accounts[1] - The contract context. Once the contract has been completed, the tokens can /// * accounts[1] - The contract context. Once the contract has been completed, the tokens can
/// be spent from this account . /// be spent from this account .
pub fn process_instruction( pub fn process_instruction(
tx: &Transaction, keyed_accounts: &mut [KeyedAccount],
instruction_index: usize, data: &[u8],
accounts: &mut [&mut Account],
) -> Result<(), BudgetError> { ) -> Result<(), BudgetError> {
if let Ok(instruction) = deserialize(tx.userdata(instruction_index)) { if let Ok(instruction) = deserialize(data) {
trace!("process_instruction: {:?}", instruction); trace!("process_instruction: {:?}", instruction);
apply_debits(tx, instruction_index, accounts, &instruction) apply_debits(keyed_accounts, &instruction)
} else { } else {
info!( info!("Invalid transaction userdata: {:?}", data);
"Invalid transaction userdata: {:?}",
tx.userdata(instruction_index)
);
Err(BudgetError::UserdataDeserializeFailure) Err(BudgetError::UserdataDeserializeFailure)
} }
} }
pub fn process( // TODO: Re-instate budget_program special case in bank.rs?
tx: &Transaction, /*
instruction_index: usize,
accounts: &mut [&mut Account],
) -> std::result::Result<(), ProgramError> {
process_instruction(&tx, instruction_index, accounts).map_err(|_| ProgramError::GenericError)
}
//TODO the contract needs to provide a "get_balance" introspection call of the userdata
pub fn get_balance(account: &Account) -> u64 { pub fn get_balance(account: &Account) -> u64 {
if let Ok(program) = deserialize(&account.userdata) { if let Ok(program) = deserialize(&account.userdata) {
let program: BudgetProgram = program; let program: BudgetProgram = program;
@ -155,6 +127,7 @@ pub fn get_balance(account: &Account) -> u64 {
account.tokens account.tokens
} }
} }
*/
impl BudgetProgram { impl BudgetProgram {
fn is_pending(&self) -> bool { fn is_pending(&self) -> bool {
@ -162,15 +135,10 @@ impl BudgetProgram {
} }
/// Process a Witness Signature. Any payment plans waiting on this signature /// Process a Witness Signature. Any payment plans waiting on this signature
/// will progress one step. /// will progress one step.
fn apply_signature( fn apply_signature(&mut self, keyed_accounts: &mut [KeyedAccount]) -> Result<(), BudgetError> {
&mut self,
tx: &Transaction,
instruction_index: usize,
accounts: &mut [&mut Account],
) -> Result<(), BudgetError> {
let mut final_payment = None; let mut final_payment = None;
if let Some(ref mut expr) = self.pending_budget { if let Some(ref mut expr) = self.pending_budget {
let key = match tx.signer_key(instruction_index, 0) { let key = match keyed_accounts[0].signer_key() {
None => return Err(BudgetError::UnsignedKey), None => return Err(BudgetError::UnsignedKey),
Some(key) => key, Some(key) => key,
}; };
@ -179,13 +147,13 @@ impl BudgetProgram {
} }
if let Some(payment) = final_payment { if let Some(payment) = final_payment {
if Some(&payment.to) != tx.key(instruction_index, 2) { if &payment.to != keyed_accounts[2].unsigned_key() {
trace!("destination missing"); trace!("destination missing");
return Err(BudgetError::DestinationMissing); return Err(BudgetError::DestinationMissing);
} }
self.pending_budget = None; self.pending_budget = None;
accounts[1].tokens -= payment.tokens; keyed_accounts[1].account.tokens -= payment.tokens;
accounts[2].tokens += payment.tokens; keyed_accounts[2].account.tokens += payment.tokens;
} }
Ok(()) Ok(())
} }
@ -194,16 +162,14 @@ impl BudgetProgram {
/// will progress one step. /// will progress one step.
fn apply_timestamp( fn apply_timestamp(
&mut self, &mut self,
tx: &Transaction, keyed_accounts: &mut [KeyedAccount],
instruction_index: usize,
accounts: &mut [&mut Account],
dt: DateTime<Utc>, dt: DateTime<Utc>,
) -> Result<(), BudgetError> { ) -> Result<(), BudgetError> {
// Check to see if any timelocked transactions can be completed. // Check to see if any timelocked transactions can be completed.
let mut final_payment = None; let mut final_payment = None;
if let Some(ref mut expr) = self.pending_budget { if let Some(ref mut expr) = self.pending_budget {
let key = match tx.signer_key(instruction_index, 0) { let key = match keyed_accounts[0].signer_key() {
None => return Err(BudgetError::UnsignedKey), None => return Err(BudgetError::UnsignedKey),
Some(key) => key, Some(key) => key,
}; };
@ -212,13 +178,13 @@ impl BudgetProgram {
} }
if let Some(payment) = final_payment { if let Some(payment) = final_payment {
if Some(&payment.to) != tx.key(instruction_index, 2) { if &payment.to != keyed_accounts[2].unsigned_key() {
trace!("destination missing"); trace!("destination missing");
return Err(BudgetError::DestinationMissing); return Err(BudgetError::DestinationMissing);
} }
self.pending_budget = None; self.pending_budget = None;
accounts[1].tokens -= payment.tokens; keyed_accounts[1].account.tokens -= payment.tokens;
accounts[2].tokens += payment.tokens; keyed_accounts[2].account.tokens += payment.tokens;
} }
Ok(()) Ok(())
} }
@ -259,22 +225,40 @@ impl BudgetProgram {
deserialize(&input[8..8 + len as usize]) deserialize(&input[8..8 + len as usize])
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use bincode::serialize; use bincode::serialize;
use budget_transaction::BudgetTransaction;
use chrono::prelude::{DateTime, NaiveDate, Utc};
use signature::GenKeys;
use solana_sdk::account::Account; use solana_sdk::account::Account;
use solana_sdk::budget_program::*;
use solana_sdk::budget_transaction::BudgetTransaction;
use solana_sdk::hash::Hash; use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::{Instruction, Transaction};
fn process_transaction(tx: &Transaction, accounts: &mut [Account]) -> Result<(), BudgetError> { fn process_transaction(
let mut refs: Vec<&mut Account> = accounts.iter_mut().collect(); tx: &Transaction,
super::process_instruction(&tx, 0, &mut refs[..]) program_accounts: &mut [Account],
) -> Result<(), BudgetError> {
assert_eq!(tx.instructions.len(), 1);
let Instruction {
ref accounts,
ref userdata,
..
} = tx.instructions[0];
let mut keyed_accounts: Vec<_> = accounts
.iter()
.map(|&index| {
let index = index as usize;
let key = &tx.account_keys[index];
(key, index < tx.signatures.len())
}).zip(program_accounts.iter_mut())
.map(|((key, is_signer), account)| KeyedAccount::new(key, is_signer, account))
.collect();
super::process_instruction(&mut keyed_accounts, &userdata)
} }
#[test] #[test]
fn test_serializer() { fn test_serializer() {
@ -574,77 +558,4 @@ mod test {
// Success if there was no panic... // Success if there was no panic...
} }
/// Detect binary changes in the serialized contract userdata, which could have a downstream
/// affect on SDKs and DApps
#[test]
fn test_sdk_serialize() {
let keypair = &GenKeys::new([0u8; 32]).gen_n_keypairs(1)[0];
let to = Pubkey::new(&[
1, 1, 1, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 8, 7, 6, 5, 4,
1, 1, 1,
]);
let contract = Pubkey::new(&[
2, 2, 2, 4, 5, 6, 7, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 8, 7, 6, 5, 4,
2, 2, 2,
]);
let date =
DateTime::<Utc>::from_utc(NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11), Utc);
let date_iso8601 = "2016-07-08T09:10:11Z";
let tx = Transaction::budget_new(&keypair, to, 192, Hash::default());
assert_eq!(
tx.userdata(0).to_vec(),
vec![2, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0]
);
assert_eq!(
tx.userdata(1).to_vec(),
vec![
0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 4, 5, 6, 7, 8, 9, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 8, 7, 6, 5, 4, 1, 1, 1
]
);
let tx = Transaction::budget_new_on_date(
&keypair,
to,
contract,
date,
keypair.pubkey(),
Some(keypair.pubkey()),
192,
Hash::default(),
);
assert_eq!(
tx.userdata(0).to_vec(),
vec![
0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 50, 48, 49, 54, 45,
48, 55, 45, 48, 56, 84, 48, 57, 58, 49, 48, 58, 49, 49, 90, 32, 253, 186, 201, 177,
11, 117, 135, 187, 167, 181, 188, 22, 59, 206, 105, 231, 150, 215, 30, 78, 212, 76,
16, 252, 180, 72, 134, 137, 247, 161, 68, 192, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 4, 5,
6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 8, 7, 6, 5, 4, 1, 1, 1, 1,
0, 0, 0, 32, 253, 186, 201, 177, 11, 117, 135, 187, 167, 181, 188, 22, 59, 206,
105, 231, 150, 215, 30, 78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161, 68, 192,
0, 0, 0, 0, 0, 0, 0, 32, 253, 186, 201, 177, 11, 117, 135, 187, 167, 181, 188, 22,
59, 206, 105, 231, 150, 215, 30, 78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161,
68
]
);
// ApplyTimestamp(date)
let tx = Transaction::budget_new_timestamp(
&keypair,
keypair.pubkey(),
to,
date,
Hash::default(),
);
let mut expected_userdata = vec![1, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0];
expected_userdata.extend(date_iso8601.as_bytes());
assert_eq!(tx.userdata(0).to_vec(), expected_userdata);
// ApplySignature
let tx = Transaction::budget_new_signature(&keypair, keypair.pubkey(), to, Hash::default());
assert_eq!(tx.userdata(0).to_vec(), vec![2, 0, 0, 0]);
}
} }

View File

@ -0,0 +1,36 @@
extern crate bincode;
extern crate chrono;
extern crate env_logger;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate solana_sdk;
mod budget_program;
use solana_sdk::account::KeyedAccount;
use solana_sdk::native_program::ProgramError;
use solana_sdk::pubkey::Pubkey;
use std::sync::{Once, ONCE_INIT};
use budget_program::process_instruction;
solana_entrypoint!(entrypoint);
fn entrypoint(
_program_id: &Pubkey,
keyed_accounts: &mut [KeyedAccount],
data: &[u8],
_tick_height: u64,
) -> Result<(), ProgramError> {
static INIT: Once = ONCE_INIT;
INIT.call_once(|| {
// env_logger can only be initialized once
env_logger::init();
});
trace!("process_instruction: {:?}", data);
trace!("keyed_accounts: {:?}", keyed_accounts);
process_instruction(keyed_accounts, data).map_err(|_| ProgramError::GenericError)
}

View File

@ -10,6 +10,7 @@ license = "Apache-2.0"
bincode = "1.0.0" bincode = "1.0.0"
byteorder = "1.2.1" byteorder = "1.2.1"
bs58 = "0.2.0" bs58 = "0.2.0"
chrono = { version = "0.4.0", features = ["serde"] }
generic-array = { version = "0.12.0", default-features = false, features = ["serde"] } generic-array = { version = "0.12.0", default-features = false, features = ["serde"] }
log = "0.4.2" log = "0.4.2"
ring = "0.13.2" ring = "0.13.2"

View File

@ -5,7 +5,7 @@
use chrono::prelude::*; use chrono::prelude::*;
use payment_plan::{Payment, Witness}; use payment_plan::{Payment, Witness};
use solana_sdk::pubkey::Pubkey; use pubkey::Pubkey;
use std::mem; use std::mem;
/// A data type representing a `Witness` that the payment plan is waiting on. /// A data type representing a `Witness` that the payment plan is waiting on.
@ -141,7 +141,7 @@ impl BudgetExpr {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use solana_sdk::signature::{Keypair, KeypairUtil}; use signature::{Keypair, KeypairUtil};
#[test] #[test]
fn test_signature_satisfied() { fn test_signature_satisfied() {

14
sdk/src/budget_program.rs Normal file
View File

@ -0,0 +1,14 @@
use pubkey::Pubkey;
pub const BUDGET_PROGRAM_ID: [u8; 32] = [
129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
];
pub fn id() -> Pubkey {
Pubkey::new(&BUDGET_PROGRAM_ID)
}
pub fn check_id(program_id: &Pubkey) -> bool {
program_id.as_ref() == BUDGET_PROGRAM_ID
}

View File

@ -5,14 +5,13 @@ use budget_expr::{BudgetExpr, Condition};
use budget_instruction::Instruction; use budget_instruction::Instruction;
use budget_program; use budget_program;
use chrono::prelude::*; use chrono::prelude::*;
use hash::Hash;
use payment_plan::Payment; use payment_plan::Payment;
use solana_sdk::hash::Hash; use pubkey::Pubkey;
use solana_sdk::pubkey::Pubkey; use signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, KeypairUtil}; use system_instruction::SystemInstruction;
use solana_sdk::system_instruction::SystemInstruction; use system_program;
use solana_sdk::system_program; use transaction::{self, Transaction};
use solana_sdk::transaction::{self, Transaction};
pub trait BudgetTransaction { pub trait BudgetTransaction {
fn budget_new_taxed( fn budget_new_taxed(

View File

@ -1,10 +1,15 @@
pub mod account; pub mod account;
pub mod bpf_loader; pub mod bpf_loader;
pub mod budget_expr;
pub mod budget_instruction;
pub mod budget_program;
pub mod budget_transaction;
pub mod hash; pub mod hash;
pub mod loader_instruction; pub mod loader_instruction;
pub mod native_loader; pub mod native_loader;
pub mod native_program; pub mod native_program;
pub mod packet; pub mod packet;
pub mod payment_plan;
pub mod pubkey; pub mod pubkey;
pub mod signature; pub mod signature;
pub mod storage_program; pub mod storage_program;
@ -18,6 +23,7 @@ pub mod vote_program;
extern crate bincode; extern crate bincode;
extern crate bs58; extern crate bs58;
extern crate byteorder; extern crate byteorder;
extern crate chrono;
extern crate generic_array; extern crate generic_array;
extern crate log; extern crate log;
extern crate ring; extern crate ring;

View File

@ -4,7 +4,7 @@
//! `Payment`, the payment is executed. //! `Payment`, the payment is executed.
use chrono::prelude::*; use chrono::prelude::*;
use solana_sdk::pubkey::Pubkey; use pubkey::Pubkey;
/// The types of events a payment plan can process. /// The types of events a payment plan can process.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]

View File

@ -5,7 +5,6 @@
use bincode::deserialize; use bincode::deserialize;
use bincode::serialize; use bincode::serialize;
use budget_program;
use counter::Counter; use counter::Counter;
use entry::Entry; use entry::Entry;
use itertools::Itertools; use itertools::Itertools;
@ -15,7 +14,6 @@ use ledger::Block;
use log::Level; use log::Level;
use mint::Mint; use mint::Mint;
use native_loader; use native_loader;
use payment_plan::Payment;
use poh_recorder::PohRecorder; use poh_recorder::PohRecorder;
use poh_service::NUM_TICKS_PER_SECOND; use poh_service::NUM_TICKS_PER_SECOND;
use rayon::prelude::*; use rayon::prelude::*;
@ -23,8 +21,10 @@ use rpc::RpcSignatureStatus;
use runtime::{self, RuntimeError}; use runtime::{self, RuntimeError};
use solana_sdk::account::Account; use solana_sdk::account::Account;
use solana_sdk::bpf_loader; use solana_sdk::bpf_loader;
use solana_sdk::budget_program;
use solana_sdk::hash::{hash, Hash}; use solana_sdk::hash::{hash, Hash};
use solana_sdk::native_program::ProgramError; use solana_sdk::native_program::ProgramError;
use solana_sdk::payment_plan::Payment;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Keypair; use solana_sdk::signature::Keypair;
use solana_sdk::signature::Signature; use solana_sdk::signature::Signature;
@ -448,6 +448,16 @@ impl Bank {
accounts.store(&bpf_loader::id(), &bpf_loader_account); accounts.store(&bpf_loader::id(), &bpf_loader_account);
// Budget program
let budget_program_account = Account {
tokens: 1,
owner: budget_program::id(),
userdata: b"solana_budget_program".to_vec(),
executable: true,
loader: native_loader::id(),
};
accounts.store(&budget_program::id(), &budget_program_account);
// Erc20 token program // Erc20 token program
let erc20_account = Account { let erc20_account = Account {
tokens: 1, tokens: 1,
@ -765,10 +775,6 @@ impl Bank {
} }
fn load_executable_accounts(&self, mut program_id: Pubkey) -> Result<Vec<(Pubkey, Account)>> { fn load_executable_accounts(&self, mut program_id: Pubkey) -> Result<Vec<(Pubkey, Account)>> {
if runtime::is_legacy_program(&program_id) {
return Ok(vec![]);
}
let mut accounts = Vec::new(); let mut accounts = Vec::new();
let mut depth = 0; let mut depth = 0;
loop { loop {
@ -1228,11 +1234,13 @@ impl Bank {
} }
pub fn read_balance(account: &Account) -> u64 { pub fn read_balance(account: &Account) -> u64 {
// TODO: Re-instate budget_program special case?
/*
if budget_program::check_id(&account.owner) { if budget_program::check_id(&account.owner) {
budget_program::get_balance(account) return budget_program::get_balance(account);
} else {
account.tokens
} }
*/
account.tokens
} }
/// Each program would need to be able to introspect its own state /// Each program would need to be able to introspect its own state
/// this is hard-coded to the Budget language /// this is hard-coded to the Budget language

View File

@ -272,9 +272,9 @@ pub fn reconstruct_entries_from_blobs(blobs: Vec<SharedBlob>) -> Result<(Vec<Ent
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use budget_transaction::BudgetTransaction;
use chrono::prelude::*; use chrono::prelude::*;
use entry::Entry; use entry::Entry;
use solana_sdk::budget_transaction::BudgetTransaction;
use solana_sdk::hash::hash; use solana_sdk::hash::hash;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::Transaction;

View File

@ -3,24 +3,24 @@
//! access read to a persistent file-based ledger. //! access read to a persistent file-based ledger.
use bincode::{self, deserialize_from, serialize_into, serialized_size}; use bincode::{self, deserialize_from, serialize_into, serialized_size};
use budget_transaction::BudgetTransaction;
use chrono::prelude::Utc; use chrono::prelude::Utc;
use entry::Entry; use entry::Entry;
use log::Level::Trace; use log::Level::Trace;
use mint::Mint; use mint::Mint;
use packet::{SharedBlob, BLOB_DATA_SIZE}; use packet::{SharedBlob, BLOB_DATA_SIZE};
use rayon::prelude::*; use rayon::prelude::*;
use solana_sdk::budget_transaction::BudgetTransaction;
use solana_sdk::hash::{hash, Hash}; use solana_sdk::hash::{hash, Hash};
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::Transaction;
use solana_sdk::vote_program::Vote;
use std::fs::{copy, create_dir_all, remove_dir_all, File, OpenOptions}; use std::fs::{copy, create_dir_all, remove_dir_all, File, OpenOptions};
use std::io::prelude::*; use std::io::prelude::*;
use std::io::{self, BufReader, BufWriter, Seek, SeekFrom}; use std::io::{self, BufReader, BufWriter, Seek, SeekFrom};
use std::mem::size_of; use std::mem::size_of;
use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::path::Path; use std::path::Path;
use solana_sdk::vote_program::Vote;
use vote_transaction::VoteTransaction; use vote_transaction::VoteTransaction;
// //
@ -701,15 +701,14 @@ pub fn make_large_test_entries(num_entries: usize) -> Vec<Entry> {
mod tests { mod tests {
use super::*; use super::*;
use bincode::{deserialize, serialized_size}; use bincode::{deserialize, serialized_size};
use budget_transaction::BudgetTransaction;
use entry::{next_entry, reconstruct_entries_from_blobs, Entry}; use entry::{next_entry, reconstruct_entries_from_blobs, Entry};
use packet::{to_blobs, BLOB_DATA_SIZE, PACKET_DATA_SIZE}; use packet::{to_blobs, BLOB_DATA_SIZE, PACKET_DATA_SIZE};
use solana_sdk::hash::hash; use solana_sdk::hash::hash;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::Transaction;
use solana_sdk::vote_program::Vote;
use std; use std;
use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use solana_sdk::vote_program::Vote;
#[test] #[test]
fn test_verify_slice() { fn test_verify_slice() {

View File

@ -14,9 +14,6 @@ pub mod banking_stage;
pub mod blob_fetch_stage; pub mod blob_fetch_stage;
pub mod bloom; pub mod bloom;
pub mod broadcast_stage; pub mod broadcast_stage;
pub mod budget_expr;
pub mod budget_instruction;
pub mod budget_transaction;
#[cfg(feature = "chacha")] #[cfg(feature = "chacha")]
pub mod chacha; pub mod chacha;
#[cfg(all(feature = "chacha", feature = "cuda"))] #[cfg(all(feature = "chacha", feature = "cuda"))]
@ -31,7 +28,6 @@ pub mod crds_traits_impls;
pub mod crds_value; pub mod crds_value;
#[macro_use] #[macro_use]
pub mod contact_info; pub mod contact_info;
pub mod budget_program;
pub mod cluster_info; pub mod cluster_info;
pub mod compute_leader_finality_service; pub mod compute_leader_finality_service;
pub mod db_ledger; pub mod db_ledger;
@ -51,7 +47,6 @@ pub mod native_loader;
pub mod ncp; pub mod ncp;
pub mod netutil; pub mod netutil;
pub mod packet; pub mod packet;
pub mod payment_plan;
pub mod poh; pub mod poh;
pub mod poh_recorder; pub mod poh_recorder;
pub mod poh_service; pub mod poh_service;

View File

@ -246,10 +246,10 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use budget_program;
use budget_transaction::BudgetTransaction;
use jsonrpc_core::futures::sync::mpsc; use jsonrpc_core::futures::sync::mpsc;
use mint::Mint; use mint::Mint;
use solana_sdk::budget_program;
use solana_sdk::budget_transaction::BudgetTransaction;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::Transaction;
use std::net::{IpAddr, Ipv4Addr}; use std::net::{IpAddr, Ipv4Addr};

View File

@ -1,4 +1,3 @@
use budget_program;
use native_loader; use native_loader;
use solana_sdk::account::{create_keyed_accounts, Account, KeyedAccount}; use solana_sdk::account::{create_keyed_accounts, Account, KeyedAccount};
use solana_sdk::native_program::ProgramError; use solana_sdk::native_program::ProgramError;
@ -13,10 +12,6 @@ pub enum RuntimeError {
ProgramError(u8, ProgramError), ProgramError(u8, ProgramError),
} }
pub fn is_legacy_program(program_id: &Pubkey) -> bool {
budget_program::check_id(program_id)
}
/// Process an instruction /// Process an instruction
/// This method calls the instruction's program entrypoint method /// This method calls the instruction's program entrypoint method
fn process_instruction( fn process_instruction(
@ -28,36 +23,25 @@ fn process_instruction(
) -> Result<(), ProgramError> { ) -> Result<(), ProgramError> {
let program_id = tx.program_id(instruction_index); let program_id = tx.program_id(instruction_index);
// Call the program method let mut keyed_accounts = create_keyed_accounts(executable_accounts);
// It's up to the program to implement its own rules on moving funds let mut keyed_accounts2: Vec<_> = tx.instructions[instruction_index]
if is_legacy_program(&program_id) { .accounts
if budget_program::check_id(&program_id) { .iter()
budget_program::process(&tx, instruction_index, program_accounts)?; .map(|&index| {
} else { let index = index as usize;
unreachable!(); let key = &tx.account_keys[index];
}; (key, index < tx.signatures.len())
Ok(()) }).zip(program_accounts.iter_mut())
} else { .map(|((key, is_signer), account)| KeyedAccount::new(key, is_signer, account))
let mut keyed_accounts = create_keyed_accounts(executable_accounts); .collect();
let mut keyed_accounts2: Vec<_> = tx.instructions[instruction_index] keyed_accounts.append(&mut keyed_accounts2);
.accounts
.iter()
.map(|&index| {
let index = index as usize;
let key = &tx.account_keys[index];
(key, index < tx.signatures.len())
}).zip(program_accounts.iter_mut())
.map(|((key, is_signer), account)| KeyedAccount::new(key, is_signer, account))
.collect();
keyed_accounts.append(&mut keyed_accounts2);
native_loader::process_instruction( native_loader::process_instruction(
&program_id, &program_id,
&mut keyed_accounts, &mut keyed_accounts,
&tx.instructions[instruction_index].userdata, &tx.instructions[instruction_index].userdata,
tick_height, tick_height,
) )
}
} }
fn verify_instruction( fn verify_instruction(

View File

@ -323,9 +323,9 @@ pub fn make_packet_from_transaction(tx: Transaction) -> Packet {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use bincode::serialize; use bincode::serialize;
use budget_program;
use packet::{Packet, SharedPackets}; use packet::{Packet, SharedPackets};
use sigverify; use sigverify;
use solana_sdk::budget_program;
use solana_sdk::hash::Hash; use solana_sdk::hash::Hash;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_instruction::SystemInstruction; use solana_sdk::system_instruction::SystemInstruction;

View File

@ -1,7 +1,5 @@
use bincode::serialize; use bincode::serialize;
use bs58; use bs58;
use budget_program;
use budget_transaction::BudgetTransaction;
use chrono::prelude::*; use chrono::prelude::*;
use clap::ArgMatches; use clap::ArgMatches;
use elf; use elf;
@ -14,6 +12,8 @@ use rpc_request::{get_rpc_request_str, RpcClient, RpcRequest};
use serde_json; use serde_json;
use solana_drone::drone::{request_airdrop_transaction, DRONE_PORT}; use solana_drone::drone::{request_airdrop_transaction, DRONE_PORT};
use solana_sdk::bpf_loader; use solana_sdk::bpf_loader;
use solana_sdk::budget_program;
use solana_sdk::budget_transaction::BudgetTransaction;
use solana_sdk::hash::Hash; use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil, Signature}; use solana_sdk::signature::{Keypair, KeypairUtil, Signature};