2020-02-04 14:54:49 -08:00
|
|
|
//! @brief Solana Native program entry point
|
|
|
|
|
2020-04-28 14:33:56 -07:00
|
|
|
use crate::{
|
|
|
|
account::Account, account::KeyedAccount, instruction::CompiledInstruction,
|
|
|
|
instruction::InstructionError, message::Message, pubkey::Pubkey,
|
|
|
|
};
|
|
|
|
use std::{cell::RefCell, rc::Rc};
|
2020-02-04 14:54:49 -08:00
|
|
|
|
|
|
|
// Prototype of a native program entry point
|
2020-03-05 10:57:35 -08:00
|
|
|
///
|
|
|
|
/// program_id: Program ID of the currently executing program
|
|
|
|
/// keyed_accounts: Accounts passed as part of the instruction
|
|
|
|
/// instruction_data: Instruction data
|
2020-04-15 09:41:29 -07:00
|
|
|
pub type ProgramEntrypoint = unsafe extern "C" fn(
|
|
|
|
program_id: &Pubkey,
|
|
|
|
keyed_accounts: &[KeyedAccount],
|
|
|
|
instruction_data: &[u8],
|
|
|
|
) -> Result<(), InstructionError>;
|
|
|
|
|
|
|
|
// Prototype of a native loader entry point
|
|
|
|
///
|
|
|
|
/// program_id: Program ID of the currently executing program
|
|
|
|
/// keyed_accounts: Accounts passed as part of the instruction
|
|
|
|
/// instruction_data: Instruction data
|
|
|
|
/// invoke_context: Invocation context
|
|
|
|
pub type LoaderEntrypoint = unsafe extern "C" fn(
|
2020-02-04 14:54:49 -08:00
|
|
|
program_id: &Pubkey,
|
|
|
|
keyed_accounts: &[KeyedAccount],
|
|
|
|
instruction_data: &[u8],
|
2020-04-28 14:33:56 -07:00
|
|
|
invoke_context: &dyn InvokeContext,
|
2020-02-04 14:54:49 -08:00
|
|
|
) -> Result<(), InstructionError>;
|
|
|
|
|
Fix hygiene issues in `declare_program!` and `declare_loader!`
The `declare_program!` and `declare_loader!` macros both expand to
new macro definitions (based on the `$name` argument). These 'inner'
macros make use of the special `$crate` metavariable to access items in
the crate where the 'inner' macros is defined.
However, this only works due to a bug in rustc. When a macro is
expanded, all `$crate` tokens in its output are 'marked' as being
resolved in the defining crate of that macro. An inner macro (including
the body of its arms) is 'just' another set of tokens that appears in
the body of the outer macro, so any `$crate` identifiers used there are
resolved relative to the 'outer' macro.
For example, consider the following code:
```rust
macro_rules! outer {
() => {
macro_rules! inner {
() => {
$crate::Foo
}
}
}
}
```
The path `$crate::Foo` will be resolved relative to the crate that defines `outer`,
**not** the crate which defines `inner`.
However, rustc currently loses this extra resolution information
(referred to as 'hygiene' information) when a crate is serialized.
In the above example, this means that the macro `inner` (which gets
defined in whatever crate invokes `outer!`) will behave differently
depending on which crate it is invoked from:
When `inner` is invoked from the same crate in which it is defined,
the hygiene information will still be available,
which will cause `$crate::Foo` to be resolved in the crate which defines 'outer'.
When `inner` is invoked from a different crate, it will be loaded from
the metadata of the crate which defines 'inner'. Since the hygiene
information is currently lost, rust will 'forget' that `$crate::Foo` is
supposed to be resolved in the context of 'outer'. Instead, it will be
resolved relative to the crate which defines 'inner', which can cause
incorrect code to compile.
This bug will soon be fixed in rust (see https://github.com/rust-lang/rust/pull/72121),
which will break `declare_program!` and `declare_loader!`. Fortunately,
it's possible to obtain the desired behavior (`$crate` resolving in the
context of the 'inner' macro) by use of a procedural macro.
This commit adds a `respan!` proc-macro to the `sdk/macro` crate.
Using the newly-stabilized (on Nightly) `Span::resolved_at` method,
the `$crate` identifier can be made to be resolved in the context of the
proper crate.
Since `Span::resolved_at` is only stable on the latest nightly,
referencing it on an earlier version of Rust will cause a compilation error.
This requires the `rustversion` crate to be used, which allows conditionally
compiling code epending on the Rust compiler version in use. Since this method is already
stabilized in the latest nightly, there will never be a situation where
the hygiene bug is fixed (e.g. https://github.com/rust-lang/rust/pull/72121)
is merged but we are unable to call `Span::resolved_at`.
2020-06-20 01:42:11 -04:00
|
|
|
#[rustversion::since(1.46.0)]
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! declare_name {
|
|
|
|
($name:ident) => {
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! $name {
|
|
|
|
() => {
|
|
|
|
// Subtle:
|
|
|
|
// The outer `declare_name!` macro may be expanded in another
|
|
|
|
// crate, causing the macro `$name!` to be defined in that
|
|
|
|
// crate. We want to emit a call to `$crate::id()`, and have
|
|
|
|
// `$crate` be resolved in the crate where `$name!` gets defined,
|
|
|
|
// *not* in this crate (where `declare_name! is defined).
|
|
|
|
//
|
|
|
|
// When a macro_rules! macro gets expanded, any $crate tokens
|
|
|
|
// in its output will be 'marked' with the crate they were expanded
|
|
|
|
// from. This includes nested macros like our macro `$name` - even
|
|
|
|
// though it looks like a separate macro, Rust considers it to be
|
|
|
|
// just another part of the output of `declare_program!`.
|
|
|
|
//
|
|
|
|
// We pass `$name` as the second argument to tell `respan!` to
|
|
|
|
// apply use the `Span` of `$name` when resolving `$crate::id`.
|
|
|
|
// This causes `$crate` to behave as though it was written
|
|
|
|
// at the same location as the `$name` value passed
|
|
|
|
// to `declare_name!` (e.g. the 'foo' in
|
|
|
|
// `declare_name(foo)`
|
|
|
|
//
|
|
|
|
// See the `respan!` macro for more details.
|
2020-07-13 20:55:29 -04:00
|
|
|
// This should use `crate::respan!` once
|
|
|
|
// https://github.com/rust-lang/rust/pull/72121 is merged:
|
|
|
|
// see https://github.com/solana-labs/solana/issues/10933.
|
2020-07-06 19:19:48 -04:00
|
|
|
// For now, we need to use `::solana_sdk`
|
|
|
|
//
|
Fix hygiene issues in `declare_program!` and `declare_loader!`
The `declare_program!` and `declare_loader!` macros both expand to
new macro definitions (based on the `$name` argument). These 'inner'
macros make use of the special `$crate` metavariable to access items in
the crate where the 'inner' macros is defined.
However, this only works due to a bug in rustc. When a macro is
expanded, all `$crate` tokens in its output are 'marked' as being
resolved in the defining crate of that macro. An inner macro (including
the body of its arms) is 'just' another set of tokens that appears in
the body of the outer macro, so any `$crate` identifiers used there are
resolved relative to the 'outer' macro.
For example, consider the following code:
```rust
macro_rules! outer {
() => {
macro_rules! inner {
() => {
$crate::Foo
}
}
}
}
```
The path `$crate::Foo` will be resolved relative to the crate that defines `outer`,
**not** the crate which defines `inner`.
However, rustc currently loses this extra resolution information
(referred to as 'hygiene' information) when a crate is serialized.
In the above example, this means that the macro `inner` (which gets
defined in whatever crate invokes `outer!`) will behave differently
depending on which crate it is invoked from:
When `inner` is invoked from the same crate in which it is defined,
the hygiene information will still be available,
which will cause `$crate::Foo` to be resolved in the crate which defines 'outer'.
When `inner` is invoked from a different crate, it will be loaded from
the metadata of the crate which defines 'inner'. Since the hygiene
information is currently lost, rust will 'forget' that `$crate::Foo` is
supposed to be resolved in the context of 'outer'. Instead, it will be
resolved relative to the crate which defines 'inner', which can cause
incorrect code to compile.
This bug will soon be fixed in rust (see https://github.com/rust-lang/rust/pull/72121),
which will break `declare_program!` and `declare_loader!`. Fortunately,
it's possible to obtain the desired behavior (`$crate` resolving in the
context of the 'inner' macro) by use of a procedural macro.
This commit adds a `respan!` proc-macro to the `sdk/macro` crate.
Using the newly-stabilized (on Nightly) `Span::resolved_at` method,
the `$crate` identifier can be made to be resolved in the context of the
proper crate.
Since `Span::resolved_at` is only stable on the latest nightly,
referencing it on an earlier version of Rust will cause a compilation error.
This requires the `rustversion` crate to be used, which allows conditionally
compiling code epending on the Rust compiler version in use. Since this method is already
stabilized in the latest nightly, there will never be a situation where
the hygiene bug is fixed (e.g. https://github.com/rust-lang/rust/pull/72121)
is merged but we are unable to call `Span::resolved_at`.
2020-06-20 01:42:11 -04:00
|
|
|
// `respan!` respans the path `$crate::id`, which we then call (hence the extra
|
|
|
|
// parens)
|
|
|
|
(
|
|
|
|
stringify!($name).to_string(),
|
|
|
|
::solana_sdk::respan!($crate::id, $name)(),
|
|
|
|
)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[rustversion::not(since(1.46.0))]
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! declare_name {
|
|
|
|
($name:ident) => {
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! $name {
|
|
|
|
() => {
|
|
|
|
(stringify!($name).to_string(), $crate::id())
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-02-04 14:54:49 -08:00
|
|
|
/// Convenience macro to declare a native program
|
|
|
|
///
|
|
|
|
/// bs58_string: bs58 string representation the program's id
|
|
|
|
/// name: Name of the program, must match the library name in Cargo.toml
|
|
|
|
/// entrypoint: Program's entrypoint, must be of `type Entrypoint`
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use std::str::FromStr;
|
|
|
|
/// # // wrapper is used so that the macro invocation occurs in the item position
|
|
|
|
/// # // rather than in the statement position which isn't allowed.
|
|
|
|
/// # mod item_wrapper {
|
|
|
|
/// use solana_sdk::account::KeyedAccount;
|
|
|
|
/// use solana_sdk::instruction::InstructionError;
|
|
|
|
/// use solana_sdk::pubkey::Pubkey;
|
|
|
|
/// use solana_sdk::declare_program;
|
|
|
|
///
|
|
|
|
/// fn my_process_instruction(
|
|
|
|
/// program_id: &Pubkey,
|
|
|
|
/// keyed_accounts: &[KeyedAccount],
|
|
|
|
/// instruction_data: &[u8],
|
|
|
|
/// ) -> Result<(), InstructionError> {
|
|
|
|
/// // Process an instruction
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// declare_program!(
|
|
|
|
/// "My11111111111111111111111111111111111111111",
|
|
|
|
/// solana_my_program,
|
|
|
|
/// my_process_instruction
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// # }
|
|
|
|
/// # use solana_sdk::pubkey::Pubkey;
|
|
|
|
/// # use item_wrapper::id;
|
|
|
|
/// let my_id = Pubkey::from_str("My11111111111111111111111111111111111111111").unwrap();
|
|
|
|
/// assert_eq!(id(), my_id);
|
|
|
|
/// ```
|
|
|
|
/// ```
|
|
|
|
/// use std::str::FromStr;
|
|
|
|
/// # // wrapper is used so that the macro invocation occurs in the item position
|
|
|
|
/// # // rather than in the statement position which isn't allowed.
|
|
|
|
/// # mod item_wrapper {
|
|
|
|
/// use solana_sdk::account::KeyedAccount;
|
|
|
|
/// use solana_sdk::instruction::InstructionError;
|
|
|
|
/// use solana_sdk::pubkey::Pubkey;
|
|
|
|
/// use solana_sdk::declare_program;
|
|
|
|
///
|
|
|
|
/// fn my_process_instruction(
|
|
|
|
/// program_id: &Pubkey,
|
|
|
|
/// keyed_accounts: &[KeyedAccount],
|
|
|
|
/// instruction_data: &[u8],
|
|
|
|
/// ) -> Result<(), InstructionError> {
|
|
|
|
/// // Process an instruction
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// declare_program!(
|
|
|
|
/// solana_sdk::system_program::ID,
|
|
|
|
/// solana_my_program,
|
|
|
|
/// my_process_instruction
|
|
|
|
/// );
|
|
|
|
/// # }
|
|
|
|
///
|
|
|
|
/// # use item_wrapper::id;
|
|
|
|
/// assert_eq!(id(), solana_sdk::system_program::ID);
|
|
|
|
/// ```
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! declare_program(
|
|
|
|
($bs58_string:expr, $name:ident, $entrypoint:expr) => (
|
|
|
|
$crate::declare_id!($bs58_string);
|
Fix hygiene issues in `declare_program!` and `declare_loader!`
The `declare_program!` and `declare_loader!` macros both expand to
new macro definitions (based on the `$name` argument). These 'inner'
macros make use of the special `$crate` metavariable to access items in
the crate where the 'inner' macros is defined.
However, this only works due to a bug in rustc. When a macro is
expanded, all `$crate` tokens in its output are 'marked' as being
resolved in the defining crate of that macro. An inner macro (including
the body of its arms) is 'just' another set of tokens that appears in
the body of the outer macro, so any `$crate` identifiers used there are
resolved relative to the 'outer' macro.
For example, consider the following code:
```rust
macro_rules! outer {
() => {
macro_rules! inner {
() => {
$crate::Foo
}
}
}
}
```
The path `$crate::Foo` will be resolved relative to the crate that defines `outer`,
**not** the crate which defines `inner`.
However, rustc currently loses this extra resolution information
(referred to as 'hygiene' information) when a crate is serialized.
In the above example, this means that the macro `inner` (which gets
defined in whatever crate invokes `outer!`) will behave differently
depending on which crate it is invoked from:
When `inner` is invoked from the same crate in which it is defined,
the hygiene information will still be available,
which will cause `$crate::Foo` to be resolved in the crate which defines 'outer'.
When `inner` is invoked from a different crate, it will be loaded from
the metadata of the crate which defines 'inner'. Since the hygiene
information is currently lost, rust will 'forget' that `$crate::Foo` is
supposed to be resolved in the context of 'outer'. Instead, it will be
resolved relative to the crate which defines 'inner', which can cause
incorrect code to compile.
This bug will soon be fixed in rust (see https://github.com/rust-lang/rust/pull/72121),
which will break `declare_program!` and `declare_loader!`. Fortunately,
it's possible to obtain the desired behavior (`$crate` resolving in the
context of the 'inner' macro) by use of a procedural macro.
This commit adds a `respan!` proc-macro to the `sdk/macro` crate.
Using the newly-stabilized (on Nightly) `Span::resolved_at` method,
the `$crate` identifier can be made to be resolved in the context of the
proper crate.
Since `Span::resolved_at` is only stable on the latest nightly,
referencing it on an earlier version of Rust will cause a compilation error.
This requires the `rustversion` crate to be used, which allows conditionally
compiling code epending on the Rust compiler version in use. Since this method is already
stabilized in the latest nightly, there will never be a situation where
the hygiene bug is fixed (e.g. https://github.com/rust-lang/rust/pull/72121)
is merged but we are unable to call `Span::resolved_at`.
2020-06-20 01:42:11 -04:00
|
|
|
$crate::declare_name!($name);
|
2020-02-04 14:54:49 -08:00
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern "C" fn $name(
|
|
|
|
program_id: &$crate::pubkey::Pubkey,
|
|
|
|
keyed_accounts: &[$crate::account::KeyedAccount],
|
|
|
|
instruction_data: &[u8],
|
|
|
|
) -> Result<(), $crate::instruction::InstructionError> {
|
|
|
|
$entrypoint(program_id, keyed_accounts, instruction_data)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
2020-04-15 09:41:29 -07:00
|
|
|
|
|
|
|
/// Same as declare_program but for native loaders
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! declare_loader(
|
|
|
|
($bs58_string:expr, $name:ident, $entrypoint:expr) => (
|
|
|
|
$crate::declare_id!($bs58_string);
|
Fix hygiene issues in `declare_program!` and `declare_loader!`
The `declare_program!` and `declare_loader!` macros both expand to
new macro definitions (based on the `$name` argument). These 'inner'
macros make use of the special `$crate` metavariable to access items in
the crate where the 'inner' macros is defined.
However, this only works due to a bug in rustc. When a macro is
expanded, all `$crate` tokens in its output are 'marked' as being
resolved in the defining crate of that macro. An inner macro (including
the body of its arms) is 'just' another set of tokens that appears in
the body of the outer macro, so any `$crate` identifiers used there are
resolved relative to the 'outer' macro.
For example, consider the following code:
```rust
macro_rules! outer {
() => {
macro_rules! inner {
() => {
$crate::Foo
}
}
}
}
```
The path `$crate::Foo` will be resolved relative to the crate that defines `outer`,
**not** the crate which defines `inner`.
However, rustc currently loses this extra resolution information
(referred to as 'hygiene' information) when a crate is serialized.
In the above example, this means that the macro `inner` (which gets
defined in whatever crate invokes `outer!`) will behave differently
depending on which crate it is invoked from:
When `inner` is invoked from the same crate in which it is defined,
the hygiene information will still be available,
which will cause `$crate::Foo` to be resolved in the crate which defines 'outer'.
When `inner` is invoked from a different crate, it will be loaded from
the metadata of the crate which defines 'inner'. Since the hygiene
information is currently lost, rust will 'forget' that `$crate::Foo` is
supposed to be resolved in the context of 'outer'. Instead, it will be
resolved relative to the crate which defines 'inner', which can cause
incorrect code to compile.
This bug will soon be fixed in rust (see https://github.com/rust-lang/rust/pull/72121),
which will break `declare_program!` and `declare_loader!`. Fortunately,
it's possible to obtain the desired behavior (`$crate` resolving in the
context of the 'inner' macro) by use of a procedural macro.
This commit adds a `respan!` proc-macro to the `sdk/macro` crate.
Using the newly-stabilized (on Nightly) `Span::resolved_at` method,
the `$crate` identifier can be made to be resolved in the context of the
proper crate.
Since `Span::resolved_at` is only stable on the latest nightly,
referencing it on an earlier version of Rust will cause a compilation error.
This requires the `rustversion` crate to be used, which allows conditionally
compiling code epending on the Rust compiler version in use. Since this method is already
stabilized in the latest nightly, there will never be a situation where
the hygiene bug is fixed (e.g. https://github.com/rust-lang/rust/pull/72121)
is merged but we are unable to call `Span::resolved_at`.
2020-06-20 01:42:11 -04:00
|
|
|
$crate::declare_name!($name);
|
|
|
|
|
2020-04-15 09:41:29 -07:00
|
|
|
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern "C" fn $name(
|
|
|
|
program_id: &$crate::pubkey::Pubkey,
|
|
|
|
keyed_accounts: &[$crate::account::KeyedAccount],
|
|
|
|
instruction_data: &[u8],
|
2020-04-28 14:33:56 -07:00
|
|
|
invoke_context: &mut dyn $crate::entrypoint_native::InvokeContext,
|
2020-04-15 09:41:29 -07:00
|
|
|
) -> Result<(), $crate::instruction::InstructionError> {
|
2020-04-28 14:33:56 -07:00
|
|
|
$entrypoint(program_id, keyed_accounts, instruction_data, invoke_context)
|
2020-04-15 09:41:29 -07:00
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
2020-04-28 14:33:56 -07:00
|
|
|
|
2020-06-03 12:48:19 -07:00
|
|
|
pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>;
|
|
|
|
|
2020-06-11 15:31:13 -07:00
|
|
|
/// Invocation context passed to loaders
|
2020-04-28 14:33:56 -07:00
|
|
|
pub trait InvokeContext {
|
2020-06-11 15:31:13 -07:00
|
|
|
/// Push a program ID on to the invocation stack
|
2020-04-28 14:33:56 -07:00
|
|
|
fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError>;
|
2020-06-11 15:31:13 -07:00
|
|
|
/// Pop a program ID off of the invocation stack
|
2020-04-28 14:33:56 -07:00
|
|
|
fn pop(&mut self);
|
2020-06-11 15:31:13 -07:00
|
|
|
/// Verify and update PreAccount state based on program execution
|
2020-04-28 14:33:56 -07:00
|
|
|
fn verify_and_update(
|
|
|
|
&mut self,
|
|
|
|
message: &Message,
|
|
|
|
instruction: &CompiledInstruction,
|
|
|
|
accounts: &[Rc<RefCell<Account>>],
|
|
|
|
) -> Result<(), InstructionError>;
|
2020-06-11 15:31:13 -07:00
|
|
|
/// Get the program ID of the currently executing program
|
2020-05-08 12:24:36 -07:00
|
|
|
fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
|
2020-06-11 15:31:13 -07:00
|
|
|
/// Get a list of built-in programs
|
2020-06-03 12:48:19 -07:00
|
|
|
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)];
|
2020-06-13 13:20:08 -07:00
|
|
|
/// Get this invocation's logger
|
|
|
|
fn get_logger(&self) -> Rc<RefCell<dyn Logger>>;
|
2020-07-29 15:29:52 -07:00
|
|
|
/// Are cross program invocations supported
|
|
|
|
fn is_cross_program_supported(&self) -> bool;
|
2020-06-13 13:20:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Log messages
|
|
|
|
pub trait Logger {
|
2020-06-06 10:18:28 -07:00
|
|
|
fn log_enabled(&self) -> bool;
|
2020-06-11 15:31:13 -07:00
|
|
|
/// Log a message
|
2020-06-06 10:18:28 -07:00
|
|
|
fn log(&mut self, message: &str);
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|