Route program_id to program entrypoint
This commit is contained in:
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -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(),
|
||||||
|
@ -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);
|
||||||
|
Reference in New Issue
Block a user