Route program_id to program entrypoint

This commit is contained in:
Michael Vines
2018-11-17 17:02:14 -08:00
committed by Grimes
parent ff386d6585
commit 3822c29415
11 changed files with 77 additions and 35 deletions

View File

@ -194,6 +194,7 @@ SOL_FN_PREFIX void _sol_panic(uint64_t line) {
*/ */
typedef struct { typedef struct {
uint64_t tick_height; /** Current ledger tick */ uint64_t tick_height; /** Current ledger tick */
const SolPubkey *program_id; /** program_id of the currently executing program */
} SolClusterInfo; } SolClusterInfo;
/** /**
@ -269,6 +270,9 @@ SOL_FN_PREFIX bool sol_deserialize(
if (cluster_info != NULL) { if (cluster_info != NULL) {
cluster_info->tick_height = *(uint64_t *) input; cluster_info->tick_height = *(uint64_t *) input;
input += sizeof(uint64_t);
cluster_info->program_id = (SolPubkey *) input;
input += sizeof(SolPubkey);
} }
return true; return true;
} }

View File

@ -15,11 +15,16 @@ extern bool entrypoint(const uint8_t *input) {
if (!sol_deserialize(input, ka, SOL_ARRAY_SIZE(ka), &ka_len, &data, &data_len, &info)) { if (!sol_deserialize(input, ka, SOL_ARRAY_SIZE(ka), &ka_len, &data, &data_len, &info)) {
return false; return false;
} }
sol_log("Tick height:");
sol_log_64(info.tick_height, 0, 0, 0, 0); sol_log_64(info.tick_height, 0, 0, 0, 0);
sol_log("Program identifier:");
sol_log_key(info.program_id);
// Log the provided account keys and instruction input data. In the case of // Log the provided account keys and instruction input data. In the case of
// the no-op program, no account keys or input data are expected but real // the no-op program, no account keys or input data are expected but real
// programs will have specific requirements so they can do their work. // programs will have specific requirements so they can do their work.
sol_log("Account keys and instruction input data:");
sol_log_params(ka, ka_len, data, data_len); sol_log_params(ka, ka_len, data, data_len);
return true; return true;
} }

View File

@ -16,11 +16,15 @@ extern bool entrypoint(const uint8_t *input) {
if (!sol_deserialize(input, ka, SOL_ARRAY_SIZE(ka), &ka_len, &data, &data_len, &info)) { if (!sol_deserialize(input, ka, SOL_ARRAY_SIZE(ka), &ka_len, &data, &data_len, &info)) {
return false; return false;
} }
sol_log("Tick height:");
sol_log_64(info.tick_height, 0, 0, 0, 0); sol_log_64(info.tick_height, 0, 0, 0, 0);
sol_log("Program identifier:");
sol_log_key(info.program_id);
// Log the provided account keys and instruction input data. In the case of // Log the provided account keys and instruction input data. In the case of
// the no-op program, no account keys or input data are expected but real // the no-op program, no account keys or input data are expected but real
// programs will have specific requirements so they can do their work. // programs will have specific requirements so they can do their work.
sol_log("Account keys and instruction input data:");
sol_log_params(ka, ka_len, data, data_len); sol_log_params(ka, ka_len, data, data_len);
return true; return true;
} }

View File

@ -99,6 +99,7 @@ pub fn create_vm(prog: &[u8]) -> Result<EbpfVmRaw, Error> {
} }
fn serialize_parameters( fn serialize_parameters(
program_id: &Pubkey,
keyed_accounts: &mut [KeyedAccount], keyed_accounts: &mut [KeyedAccount],
data: &[u8], data: &[u8],
tick_height: u64, tick_height: u64,
@ -119,6 +120,7 @@ fn serialize_parameters(
v.write_u64::<LittleEndian>(data.len() as u64).unwrap(); v.write_u64::<LittleEndian>(data.len() as u64).unwrap();
v.write_all(data).unwrap(); v.write_all(data).unwrap();
v.write_u64::<LittleEndian>(tick_height).unwrap(); v.write_u64::<LittleEndian>(tick_height).unwrap();
v.write_all(program_id.as_ref()).unwrap();
v v
} }
@ -141,7 +143,12 @@ fn deserialize_parameters(keyed_accounts: &mut [KeyedAccount], buffer: &[u8]) {
} }
solana_entrypoint!(entrypoint); solana_entrypoint!(entrypoint);
fn entrypoint(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8], tick_height: u64) -> bool { fn entrypoint(
program_id: &Pubkey,
keyed_accounts: &mut [KeyedAccount],
tx_data: &[u8],
tick_height: u64,
) -> bool {
static INIT: Once = ONCE_INIT; static INIT: Once = ONCE_INIT;
INIT.call_once(|| { INIT.call_once(|| {
// env_logger can only be initialized once // env_logger can only be initialized once
@ -159,7 +166,8 @@ fn entrypoint(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8], tick_height:
return false; return false;
} }
}; };
let mut v = serialize_parameters(&mut keyed_accounts[1..], &tx_data, tick_height); let mut v =
serialize_parameters(program_id, &mut keyed_accounts[1..], &tx_data, tick_height);
match vm.execute_program(v.as_mut_slice()) { match vm.execute_program(v.as_mut_slice()) {
Ok(status) => { Ok(status) => {
if 0 == status { if 0 == status {

View File

@ -11,17 +11,23 @@ extern crate serde_derive;
extern crate solana_sdk; extern crate solana_sdk;
use solana_sdk::account::KeyedAccount; use solana_sdk::account::KeyedAccount;
use solana_sdk::pubkey::Pubkey;
use std::sync::{Once, ONCE_INIT}; use std::sync::{Once, ONCE_INIT};
mod token_program; mod token_program;
solana_entrypoint!(entrypoint); solana_entrypoint!(entrypoint);
fn entrypoint(info: &mut [KeyedAccount], input: &[u8], _tick_height: u64) -> bool { fn entrypoint(
program_id: &Pubkey,
info: &mut [KeyedAccount],
input: &[u8],
_tick_height: u64,
) -> bool {
// env_logger can only be initialized once // env_logger can only be initialized once
static INIT: Once = ONCE_INIT; static INIT: Once = ONCE_INIT;
INIT.call_once(env_logger::init); INIT.call_once(env_logger::init);
match token_program::TokenProgram::process(info, input) { match token_program::TokenProgram::process(program_id, info, input) {
Err(err) => { Err(err) => {
error!("error: {:?}", err); error!("error: {:?}", err);
false false

View File

@ -402,7 +402,7 @@ impl TokenProgram {
Ok(()) Ok(())
} }
pub fn process(info: &mut [KeyedAccount], input: &[u8]) -> Result<()> { pub fn process(program_id: &Pubkey, info: &mut [KeyedAccount], input: &[u8]) -> Result<()> {
let command = bincode::deserialize::<Command>(input).map_err(Self::map_to_invalid_args)?; let command = bincode::deserialize::<Command>(input).map_err(Self::map_to_invalid_args)?;
info!("process_transaction: command={:?}", command); info!("process_transaction: command={:?}", command);
@ -410,13 +410,7 @@ impl TokenProgram {
.iter() .iter()
.map(|keyed_account| { .map(|keyed_account| {
let account = &keyed_account.account; let account = &keyed_account.account;
if account.owner == *program_id {
//
// TODO: Restore the following commented out block to valid program ids
// once https://github.com/solana-labs/solana/issues/1544 is fixed.
/*
if account.program_id == info[0].account.program_id {
match Self::deserialize(&account.userdata) { match Self::deserialize(&account.userdata) {
Ok(token_program) => token_program, Ok(token_program) => token_program,
Err(err) => { Err(err) => {
@ -427,14 +421,6 @@ impl TokenProgram {
} else { } else {
TokenProgram::Invalid TokenProgram::Invalid
} }
*/
match Self::deserialize(&account.userdata) {
Ok(token_program) => token_program,
Err(err) => {
error!("deserialize failed: {:?}", err);
TokenProgram::Invalid
}
}
}).collect(); }).collect();
for program_account in &input_program_accounts { for program_account in &input_program_accounts {

View File

@ -10,6 +10,7 @@ use bincode::deserialize;
use rlua::{Lua, Result, Table}; use rlua::{Lua, Result, Table};
use solana_sdk::account::KeyedAccount; use solana_sdk::account::KeyedAccount;
use solana_sdk::loader_instruction::LoaderInstruction; use solana_sdk::loader_instruction::LoaderInstruction;
use solana_sdk::pubkey::Pubkey;
use std::str; use std::str;
use std::sync::{Once, ONCE_INIT}; use std::sync::{Once, ONCE_INIT};
@ -53,7 +54,12 @@ fn run_lua(keyed_accounts: &mut [KeyedAccount], code: &str, data: &[u8]) -> Resu
} }
solana_entrypoint!(entrypoint); solana_entrypoint!(entrypoint);
fn entrypoint(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8], _tick_height: u64) -> bool { fn entrypoint(
_program_id: &Pubkey,
keyed_accounts: &mut [KeyedAccount],
tx_data: &[u8],
_tick_height: u64,
) -> bool {
static INIT: Once = ONCE_INIT; static INIT: Once = ONCE_INIT;
INIT.call_once(|| { INIT.call_once(|| {
// env_logger can only be initialized once // env_logger can only be initialized once
@ -174,11 +180,11 @@ mod tests {
(bob_pubkey, Account::new(1, 0, owner)), (bob_pubkey, Account::new(1, 0, owner)),
]; ];
let data = serialize(&10u64).unwrap(); let data = serialize(&10u64).unwrap();
process(&mut create_keyed_accounts(&mut accounts), &data, 0); process(&owner, &mut create_keyed_accounts(&mut accounts), &data, 0);
assert_eq!(accounts[1].1.tokens, 90); assert_eq!(accounts[1].1.tokens, 90);
assert_eq!(accounts[2].1.tokens, 11); assert_eq!(accounts[2].1.tokens, 11);
process(&mut create_keyed_accounts(&mut accounts), &data, 0); process(&owner, &mut create_keyed_accounts(&mut accounts), &data, 0);
assert_eq!(accounts[1].1.tokens, 80); assert_eq!(accounts[1].1.tokens, 80);
assert_eq!(accounts[2].1.tokens, 21); assert_eq!(accounts[2].1.tokens, 21);
} }
@ -222,7 +228,7 @@ mod tests {
(Pubkey::default(), Account::new(1, 0, owner)), (Pubkey::default(), Account::new(1, 0, owner)),
]; ];
let mut keyed_accounts = create_keyed_accounts(&mut accounts); let mut keyed_accounts = create_keyed_accounts(&mut accounts);
process(&mut keyed_accounts, &[], 0); process(&owner, &mut keyed_accounts, &[], 0);
// Verify deterministic ordering of a serialized Lua table. // Verify deterministic ordering of a serialized Lua table.
assert_eq!( assert_eq!(
str::from_utf8(&keyed_accounts[3].account.userdata).unwrap(), str::from_utf8(&keyed_accounts[3].account.userdata).unwrap(),
@ -281,19 +287,19 @@ mod tests {
).as_bytes() ).as_bytes()
.to_vec(); .to_vec();
process(&mut keyed_accounts, &data, 0); process(&owner, &mut keyed_accounts, &data, 0);
assert_eq!(keyed_accounts[4].account.tokens, 1); assert_eq!(keyed_accounts[4].account.tokens, 1);
let data = format!(r#""{}""#, carol_pubkey).into_bytes(); let data = format!(r#""{}""#, carol_pubkey).into_bytes();
process(&mut keyed_accounts, &data, 0); process(&owner, &mut keyed_accounts, &data, 0);
assert_eq!(keyed_accounts[4].account.tokens, 1); assert_eq!(keyed_accounts[4].account.tokens, 1);
let data = format!(r#""{}""#, dan_pubkey).into_bytes(); let data = format!(r#""{}""#, dan_pubkey).into_bytes();
process(&mut keyed_accounts, &data, 0); process(&owner, &mut keyed_accounts, &data, 0);
assert_eq!(keyed_accounts[4].account.tokens, 101); // Pay day! assert_eq!(keyed_accounts[4].account.tokens, 101); // Pay day!
let data = format!(r#""{}""#, erin_pubkey).into_bytes(); let data = format!(r#""{}""#, erin_pubkey).into_bytes();
process(&mut keyed_accounts, &data, 0); process(&owner, &mut keyed_accounts, &data, 0);
assert_eq!(keyed_accounts[4].account.tokens, 101); // No change! assert_eq!(keyed_accounts[4].account.tokens, 101); // No change!
} }
} }

View File

@ -2,9 +2,16 @@
extern crate solana_sdk; extern crate solana_sdk;
use solana_sdk::account::KeyedAccount; use solana_sdk::account::KeyedAccount;
use solana_sdk::pubkey::Pubkey;
solana_entrypoint!(entrypoint); solana_entrypoint!(entrypoint);
fn entrypoint(keyed_accounts: &mut [KeyedAccount], data: &[u8], tick_height: u64) -> bool { fn entrypoint(
program_id: &Pubkey,
keyed_accounts: &mut [KeyedAccount],
data: &[u8],
tick_height: u64,
) -> bool {
println!("noop: program_id: {:?}", program_id);
println!("noop: keyed_accounts: {:#?}", keyed_accounts); println!("noop: keyed_accounts: {:#?}", keyed_accounts);
println!("noop: data: {:?}", data); println!("noop: data: {:?}", data);
println!("noop: tick_height: {:?}", tick_height); println!("noop: tick_height: {:?}", tick_height);

View File

@ -1,12 +1,16 @@
use account::KeyedAccount; use account::KeyedAccount;
use pubkey::Pubkey;
// All native programs export a symbol named process() // All native programs export a symbol named process()
pub const ENTRYPOINT: &str = "process"; pub const ENTRYPOINT: &str = "process";
// Native program ENTRYPOINT prototype // Native program ENTRYPOINT prototype
pub type Entrypoint = pub type Entrypoint = unsafe extern "C" fn(
unsafe extern "C" fn(keyed_accounts: &mut [KeyedAccount], data: &[u8], tick_height: u64) program_id: &Pubkey,
-> bool; keyed_accounts: &mut [KeyedAccount],
data: &[u8],
tick_height: u64,
) -> bool;
// Convenience macro to define the native program entrypoint. Supply a fn to this macro that // Convenience macro to define the native program entrypoint. Supply a fn to this macro that
// conforms to the `Entrypoint` type signature. // conforms to the `Entrypoint` type signature.
@ -14,8 +18,13 @@ pub type Entrypoint =
macro_rules! solana_entrypoint( macro_rules! solana_entrypoint(
($entrypoint:ident) => ( ($entrypoint:ident) => (
#[no_mangle] #[no_mangle]
pub extern "C" fn process(keyed_accounts: &mut [KeyedAccount], data: &[u8], tick_height: u64) -> bool { pub extern "C" fn process(
return $entrypoint(keyed_accounts, data, tick_height); program_id: &Pubkey,
keyed_accounts: &mut [KeyedAccount],
data: &[u8],
tick_height: u64
) -> bool {
return $entrypoint(program_id, keyed_accounts, data, tick_height);
} }
) )
); );

View File

@ -854,6 +854,7 @@ impl Bank {
keyed_accounts.append(&mut keyed_accounts2); keyed_accounts.append(&mut keyed_accounts2);
if !native_loader::process_instruction( if !native_loader::process_instruction(
&program_id,
&mut keyed_accounts, &mut keyed_accounts,
&tx.instructions[instruction_index].userdata, &tx.instructions[instruction_index].userdata,
self.tick_height(), self.tick_height(),

View File

@ -54,6 +54,7 @@ pub fn id() -> Pubkey {
} }
pub fn process_instruction( pub fn process_instruction(
program_id: &Pubkey,
keyed_accounts: &mut [KeyedAccount], keyed_accounts: &mut [KeyedAccount],
ix_userdata: &[u8], ix_userdata: &[u8],
tick_height: u64, tick_height: u64,
@ -85,7 +86,12 @@ pub fn process_instruction(
return false; return false;
} }
}; };
return entrypoint(&mut keyed_accounts[1..], ix_userdata, tick_height); return entrypoint(
program_id,
&mut keyed_accounts[1..],
ix_userdata,
tick_height,
);
}, },
Err(e) => { Err(e) => {
warn!("Unable to load: {:?}", e); warn!("Unable to load: {:?}", e);