Introducing Scripts

A sequence of instructions. A client compiles the script and then uses
the compiled script to construction a transaction. Then it adds a
adds a blockhash, signs the transaction, and sends it off for
processing.
This commit is contained in:
Greg Fitzgerald
2019-03-16 14:30:10 -06:00
committed by Grimes
parent 55cdbedb52
commit ae4d14a2ad
6 changed files with 268 additions and 178 deletions

View File

@ -1,9 +1,12 @@
use crate::budget_expr::BudgetExpr;
use crate::budget_expr::{BudgetExpr, Condition};
use crate::budget_state::BudgetState;
use crate::id;
use bincode::serialized_size;
use chrono::prelude::{DateTime, Utc};
use serde_derive::{Deserialize, Serialize};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::transaction::Instruction;
use solana_sdk::system_instruction::SystemInstruction;
use solana_sdk::transaction::{Instruction, Script};
/// A smart contract.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
@ -37,6 +40,80 @@ impl BudgetInstruction {
Instruction::new(id(), &BudgetInstruction::InitializeAccount(expr), keys)
}
pub fn new_initialize_account_script(
from: &Pubkey,
contract: &Pubkey,
lamports: u64,
expr: BudgetExpr,
) -> Script {
let space = serialized_size(&BudgetState::new(expr.clone())).unwrap();
vec![
SystemInstruction::new_program_account(&from, contract, lamports, space, &id()),
Self::new_initialize_account(contract, expr),
]
}
/// Create a postdated payment script.
pub fn new_on_date_script(
from: &Pubkey,
to: &Pubkey,
contract: &Pubkey,
dt: DateTime<Utc>,
dt_pubkey: &Pubkey,
cancelable: Option<Pubkey>,
lamports: u64,
) -> Script {
let expr = if let Some(from) = cancelable {
BudgetExpr::Or(
(
Condition::Timestamp(dt, *dt_pubkey),
Box::new(BudgetExpr::new_payment(lamports, to)),
),
(
Condition::Signature(from),
Box::new(BudgetExpr::new_payment(lamports, &from)),
),
)
} else {
BudgetExpr::After(
Condition::Timestamp(dt, *dt_pubkey),
Box::new(BudgetExpr::new_payment(lamports, to)),
)
};
Self::new_initialize_account_script(from, contract, lamports, expr)
}
/// Create a multisig payment script.
pub fn new_when_signed_script(
from: &Pubkey,
to: &Pubkey,
contract: &Pubkey,
witness: &Pubkey,
cancelable: Option<Pubkey>,
lamports: u64,
) -> Script {
let expr = if let Some(from) = cancelable {
BudgetExpr::Or(
(
Condition::Signature(*witness),
Box::new(BudgetExpr::new_payment(lamports, to)),
),
(
Condition::Signature(from),
Box::new(BudgetExpr::new_payment(lamports, &from)),
),
)
} else {
BudgetExpr::After(
Condition::Signature(*witness),
Box::new(BudgetExpr::new_payment(lamports, to)),
)
};
Self::new_initialize_account_script(from, contract, lamports, expr)
}
pub fn new_apply_timestamp(
from: &Pubkey,
contract: &Pubkey,

View File

@ -1,6 +1,6 @@
//! The `budget_transaction` module provides functionality for creating Budget transactions.
use crate::budget_expr::{BudgetExpr, Condition};
use crate::budget_expr::BudgetExpr;
use crate::budget_instruction::BudgetInstruction;
use crate::budget_state::BudgetState;
use crate::id;
@ -10,7 +10,7 @@ use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_instruction::SystemInstruction;
use solana_sdk::transaction::Transaction;
use solana_sdk::transaction::{Script, Transaction};
pub struct BudgetTransaction {}
@ -36,6 +36,18 @@ impl BudgetTransaction {
tx
}
fn new_signed(
from_keypair: &Keypair,
script: Script,
recent_blockhash: Hash,
fee: u64,
) -> Transaction {
let mut tx = Transaction::new(script);
tx.fee = fee;
tx.sign(&[from_keypair], recent_blockhash);
tx
}
/// Create and sign a new Transaction. Used for unit-testing.
pub fn new_payment(
from_keypair: &Keypair,
@ -96,24 +108,16 @@ impl BudgetTransaction {
lamports: u64,
recent_blockhash: Hash,
) -> Transaction {
let expr = if let Some(from) = cancelable {
BudgetExpr::Or(
(
Condition::Timestamp(dt, *dt_pubkey),
Box::new(BudgetExpr::new_payment(lamports, to)),
),
(
Condition::Signature(from),
Box::new(BudgetExpr::new_payment(lamports, &from)),
),
)
} else {
BudgetExpr::After(
Condition::Timestamp(dt, *dt_pubkey),
Box::new(BudgetExpr::new_payment(lamports, to)),
)
};
Self::new(from_keypair, contract, expr, lamports, recent_blockhash, 0)
let script = BudgetInstruction::new_on_date_script(
&from_keypair.pubkey(),
to,
contract,
dt,
dt_pubkey,
cancelable,
lamports,
);
Self::new_signed(from_keypair, script, recent_blockhash, 0)
}
/// Create and sign a multisig Transaction.
@ -126,24 +130,15 @@ impl BudgetTransaction {
lamports: u64,
recent_blockhash: Hash,
) -> Transaction {
let expr = if let Some(from) = cancelable {
BudgetExpr::Or(
(
Condition::Signature(*witness),
Box::new(BudgetExpr::new_payment(lamports, to)),
),
(
Condition::Signature(from),
Box::new(BudgetExpr::new_payment(lamports, &from)),
),
)
} else {
BudgetExpr::After(
Condition::Signature(*witness),
Box::new(BudgetExpr::new_payment(lamports, to)),
)
};
Self::new(from_keypair, contract, expr, lamports, recent_blockhash, 0)
let script = BudgetInstruction::new_when_signed_script(
&from_keypair.pubkey(),
to,
contract,
witness,
cancelable,
lamports,
);
Self::new_signed(from_keypair, script, recent_blockhash, 0)
}
pub fn system_instruction(tx: &Transaction, index: usize) -> Option<SystemInstruction> {