Support using Squads multisig with sealevel tooling, support ownership transfers in tooling (#2700)
### Description Sadly, there's no programmatic way to submit transactions to Squads via an API or anything. As a workaround, if `-k` is passed a Pubkey and not a path to a Keypair as the payer, transactions will instead be logged in a base58 serialized format that can then be copied into Squads. Instructions for exactly how to do this are found in our Notion So this includes: * Allow for the payer to just be a Pubkey without a Keypair * Some commands & functions to allow for ownership transfer ### Drive-by changes * There was a whole directory `rust/chains/hyperlane-sealevel/src/solana` that somehow got into main, I deleted this * Cleaned up some logs to be formatted more nicely ### Related issues part of https://github.com/hyperlane-xyz/issues/issues/545 ### Backward compatibility backward compatible ### Testing Transferred ownership of devnet --------- Co-authored-by: Daniel Savu <23065004+daniel-savu@users.noreply.github.com>pull/2704/head
parent
71e8988ccd
commit
2d8fced77a
@ -1,7 +0,0 @@ |
||||
//! The [ed25519 native program][np].
|
||||
//!
|
||||
//! [np]: https://docs.solana.com/developing/runtime-facilities/programs#ed25519-program
|
||||
use crate::solana::pubkey::Pubkey; |
||||
use solana_sdk_macro::declare_id; |
||||
|
||||
declare_id!("Ed25519SigVerify111111111111111111111111111"); |
@ -1,360 +0,0 @@ |
||||
//! Calculation of transaction fees.
|
||||
|
||||
#![allow(clippy::integer_arithmetic)] |
||||
|
||||
use serde_derive::{Deserialize, Serialize}; |
||||
|
||||
use super::{ed25519_program, message::Message, secp256k1_program}; |
||||
// use super::
|
||||
use log::*; |
||||
|
||||
#[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug)] |
||||
#[serde(rename_all = "camelCase")] |
||||
pub struct FeeCalculator { |
||||
/// The current cost of a signature.
|
||||
///
|
||||
/// This amount may increase/decrease over time based on cluster processing
|
||||
/// load.
|
||||
pub lamports_per_signature: u64, |
||||
} |
||||
|
||||
impl FeeCalculator { |
||||
pub fn new(lamports_per_signature: u64) -> Self { |
||||
Self { |
||||
lamports_per_signature, |
||||
} |
||||
} |
||||
|
||||
#[deprecated(
|
||||
since = "1.9.0", |
||||
note = "Please do not use, will no longer be available in the future" |
||||
)] |
||||
pub fn calculate_fee(&self, message: &Message) -> u64 { |
||||
let mut num_signatures: u64 = 0; |
||||
for instruction in &message.instructions { |
||||
let program_index = instruction.program_id_index as usize; |
||||
// Message may not be sanitized here
|
||||
if program_index < message.account_keys.len() { |
||||
let id = message.account_keys[program_index]; |
||||
if (secp256k1_program::check_id(&id) || ed25519_program::check_id(&id)) |
||||
&& !instruction.data.is_empty() |
||||
{ |
||||
num_signatures += instruction.data[0] as u64; |
||||
} |
||||
} |
||||
} |
||||
|
||||
self.lamports_per_signature |
||||
* (u64::from(message.header.num_required_signatures) + num_signatures) |
||||
} |
||||
} |
||||
|
||||
/* |
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug, AbiExample)] |
||||
#[serde(rename_all = "camelCase")] |
||||
pub struct FeeRateGovernor { |
||||
// The current cost of a signature This amount may increase/decrease over time based on
|
||||
// cluster processing load.
|
||||
#[serde(skip)] |
||||
pub lamports_per_signature: u64, |
||||
|
||||
// The target cost of a signature when the cluster is operating around target_signatures_per_slot
|
||||
// signatures
|
||||
pub target_lamports_per_signature: u64, |
||||
|
||||
// Used to estimate the desired processing capacity of the cluster. As the signatures for
|
||||
// recent slots are fewer/greater than this value, lamports_per_signature will decrease/increase
|
||||
// for the next slot. A value of 0 disables lamports_per_signature fee adjustments
|
||||
pub target_signatures_per_slot: u64, |
||||
|
||||
pub min_lamports_per_signature: u64, |
||||
pub max_lamports_per_signature: u64, |
||||
|
||||
// What portion of collected fees are to be destroyed, as a fraction of std::u8::MAX
|
||||
pub burn_percent: u8, |
||||
} |
||||
|
||||
pub const DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE: u64 = 10_000; |
||||
pub const DEFAULT_TARGET_SIGNATURES_PER_SLOT: u64 = 50 * DEFAULT_MS_PER_SLOT; |
||||
|
||||
// Percentage of tx fees to burn
|
||||
pub const DEFAULT_BURN_PERCENT: u8 = 50; |
||||
|
||||
impl Default for FeeRateGovernor { |
||||
fn default() -> Self { |
||||
Self { |
||||
lamports_per_signature: 0, |
||||
target_lamports_per_signature: DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE, |
||||
target_signatures_per_slot: DEFAULT_TARGET_SIGNATURES_PER_SLOT, |
||||
min_lamports_per_signature: 0, |
||||
max_lamports_per_signature: 0, |
||||
burn_percent: DEFAULT_BURN_PERCENT, |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl FeeRateGovernor { |
||||
pub fn new(target_lamports_per_signature: u64, target_signatures_per_slot: u64) -> Self { |
||||
let base_fee_rate_governor = Self { |
||||
target_lamports_per_signature, |
||||
lamports_per_signature: target_lamports_per_signature, |
||||
target_signatures_per_slot, |
||||
..FeeRateGovernor::default() |
||||
}; |
||||
|
||||
Self::new_derived(&base_fee_rate_governor, 0) |
||||
} |
||||
|
||||
pub fn new_derived( |
||||
base_fee_rate_governor: &FeeRateGovernor, |
||||
latest_signatures_per_slot: u64, |
||||
) -> Self { |
||||
let mut me = base_fee_rate_governor.clone(); |
||||
|
||||
if me.target_signatures_per_slot > 0 { |
||||
// lamports_per_signature can range from 50% to 1000% of
|
||||
// target_lamports_per_signature
|
||||
me.min_lamports_per_signature = std::cmp::max(1, me.target_lamports_per_signature / 2); |
||||
me.max_lamports_per_signature = me.target_lamports_per_signature * 10; |
||||
|
||||
// What the cluster should charge at `latest_signatures_per_slot`
|
||||
let desired_lamports_per_signature = |
||||
me.max_lamports_per_signature |
||||
.min(me.min_lamports_per_signature.max( |
||||
me.target_lamports_per_signature |
||||
* std::cmp::min(latest_signatures_per_slot, std::u32::MAX as u64) |
||||
as u64 |
||||
/ me.target_signatures_per_slot as u64, |
||||
)); |
||||
|
||||
trace!( |
||||
"desired_lamports_per_signature: {}", |
||||
desired_lamports_per_signature |
||||
); |
||||
|
||||
let gap = desired_lamports_per_signature as i64 |
||||
- base_fee_rate_governor.lamports_per_signature as i64; |
||||
|
||||
if gap == 0 { |
||||
me.lamports_per_signature = desired_lamports_per_signature; |
||||
} else { |
||||
// Adjust fee by 5% of target_lamports_per_signature to produce a smooth
|
||||
// increase/decrease in fees over time.
|
||||
let gap_adjust = |
||||
std::cmp::max(1, me.target_lamports_per_signature / 20) as i64 * gap.signum(); |
||||
|
||||
trace!( |
||||
"lamports_per_signature gap is {}, adjusting by {}", |
||||
gap, |
||||
gap_adjust |
||||
); |
||||
|
||||
me.lamports_per_signature = |
||||
me.max_lamports_per_signature |
||||
.min(me.min_lamports_per_signature.max( |
||||
(base_fee_rate_governor.lamports_per_signature as i64 + gap_adjust) |
||||
as u64, |
||||
)); |
||||
} |
||||
} else { |
||||
me.lamports_per_signature = base_fee_rate_governor.target_lamports_per_signature; |
||||
me.min_lamports_per_signature = me.target_lamports_per_signature; |
||||
me.max_lamports_per_signature = me.target_lamports_per_signature; |
||||
} |
||||
debug!( |
||||
"new_derived(): lamports_per_signature: {}", |
||||
me.lamports_per_signature |
||||
); |
||||
me |
||||
} |
||||
|
||||
pub fn clone_with_lamports_per_signature(&self, lamports_per_signature: u64) -> Self { |
||||
Self { |
||||
lamports_per_signature, |
||||
..*self |
||||
} |
||||
} |
||||
|
||||
/// calculate unburned fee from a fee total, returns (unburned, burned)
|
||||
pub fn burn(&self, fees: u64) -> (u64, u64) { |
||||
let burned = fees * u64::from(self.burn_percent) / 100; |
||||
(fees - burned, burned) |
||||
} |
||||
|
||||
/// create a FeeCalculator based on current cluster signature throughput
|
||||
pub fn create_fee_calculator(&self) -> FeeCalculator { |
||||
FeeCalculator::new(self.lamports_per_signature) |
||||
} |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod tests { |
||||
use { |
||||
super::*, |
||||
crate::{pubkey::Pubkey, system_instruction}, |
||||
}; |
||||
|
||||
#[test] |
||||
fn test_fee_rate_governor_burn() { |
||||
let mut fee_rate_governor = FeeRateGovernor::default(); |
||||
assert_eq!(fee_rate_governor.burn(2), (1, 1)); |
||||
|
||||
fee_rate_governor.burn_percent = 0; |
||||
assert_eq!(fee_rate_governor.burn(2), (2, 0)); |
||||
|
||||
fee_rate_governor.burn_percent = 100; |
||||
assert_eq!(fee_rate_governor.burn(2), (0, 2)); |
||||
} |
||||
|
||||
#[test] |
||||
#[allow(deprecated)] |
||||
fn test_fee_calculator_calculate_fee() { |
||||
// Default: no fee.
|
||||
let message = Message::default(); |
||||
assert_eq!(FeeCalculator::default().calculate_fee(&message), 0); |
||||
|
||||
// No signature, no fee.
|
||||
assert_eq!(FeeCalculator::new(1).calculate_fee(&message), 0); |
||||
|
||||
// One signature, a fee.
|
||||
let pubkey0 = Pubkey::new(&[0; 32]); |
||||
let pubkey1 = Pubkey::new(&[1; 32]); |
||||
let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1); |
||||
let message = Message::new(&[ix0], Some(&pubkey0)); |
||||
assert_eq!(FeeCalculator::new(2).calculate_fee(&message), 2); |
||||
|
||||
// Two signatures, double the fee.
|
||||
let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1); |
||||
let ix1 = system_instruction::transfer(&pubkey1, &pubkey0, 1); |
||||
let message = Message::new(&[ix0, ix1], Some(&pubkey0)); |
||||
assert_eq!(FeeCalculator::new(2).calculate_fee(&message), 4); |
||||
} |
||||
|
||||
#[test] |
||||
#[allow(deprecated)] |
||||
fn test_fee_calculator_calculate_fee_secp256k1() { |
||||
use crate::instruction::Instruction; |
||||
let pubkey0 = Pubkey::new(&[0; 32]); |
||||
let pubkey1 = Pubkey::new(&[1; 32]); |
||||
let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1); |
||||
let mut secp_instruction = Instruction { |
||||
program_id: crate::secp256k1_program::id(), |
||||
accounts: vec![], |
||||
data: vec![], |
||||
}; |
||||
let mut secp_instruction2 = Instruction { |
||||
program_id: crate::secp256k1_program::id(), |
||||
accounts: vec![], |
||||
data: vec![1], |
||||
}; |
||||
|
||||
let message = Message::new( |
||||
&[ |
||||
ix0.clone(), |
||||
secp_instruction.clone(), |
||||
secp_instruction2.clone(), |
||||
], |
||||
Some(&pubkey0), |
||||
); |
||||
assert_eq!(FeeCalculator::new(1).calculate_fee(&message), 2); |
||||
|
||||
secp_instruction.data = vec![0]; |
||||
secp_instruction2.data = vec![10]; |
||||
let message = Message::new(&[ix0, secp_instruction, secp_instruction2], Some(&pubkey0)); |
||||
assert_eq!(FeeCalculator::new(1).calculate_fee(&message), 11); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_fee_rate_governor_derived_default() { |
||||
solana_logger::setup(); |
||||
|
||||
let f0 = FeeRateGovernor::default(); |
||||
assert_eq!( |
||||
f0.target_signatures_per_slot, |
||||
DEFAULT_TARGET_SIGNATURES_PER_SLOT |
||||
); |
||||
assert_eq!( |
||||
f0.target_lamports_per_signature, |
||||
DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE |
||||
); |
||||
assert_eq!(f0.lamports_per_signature, 0); |
||||
|
||||
let f1 = FeeRateGovernor::new_derived(&f0, DEFAULT_TARGET_SIGNATURES_PER_SLOT); |
||||
assert_eq!( |
||||
f1.target_signatures_per_slot, |
||||
DEFAULT_TARGET_SIGNATURES_PER_SLOT |
||||
); |
||||
assert_eq!( |
||||
f1.target_lamports_per_signature, |
||||
DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE |
||||
); |
||||
assert_eq!( |
||||
f1.lamports_per_signature, |
||||
DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE / 2 |
||||
); // min
|
||||
} |
||||
|
||||
#[test] |
||||
fn test_fee_rate_governor_derived_adjust() { |
||||
solana_logger::setup(); |
||||
|
||||
let mut f = FeeRateGovernor { |
||||
target_lamports_per_signature: 100, |
||||
target_signatures_per_slot: 100, |
||||
..FeeRateGovernor::default() |
||||
}; |
||||
f = FeeRateGovernor::new_derived(&f, 0); |
||||
|
||||
// Ramp fees up
|
||||
let mut count = 0; |
||||
loop { |
||||
let last_lamports_per_signature = f.lamports_per_signature; |
||||
|
||||
f = FeeRateGovernor::new_derived(&f, std::u64::MAX); |
||||
info!("[up] f.lamports_per_signature={}", f.lamports_per_signature); |
||||
|
||||
// some maximum target reached
|
||||
if f.lamports_per_signature == last_lamports_per_signature { |
||||
break; |
||||
} |
||||
// shouldn't take more than 1000 steps to get to minimum
|
||||
assert!(count < 1000); |
||||
count += 1; |
||||
} |
||||
|
||||
// Ramp fees down
|
||||
let mut count = 0; |
||||
loop { |
||||
let last_lamports_per_signature = f.lamports_per_signature; |
||||
f = FeeRateGovernor::new_derived(&f, 0); |
||||
|
||||
info!( |
||||
"[down] f.lamports_per_signature={}", |
||||
f.lamports_per_signature |
||||
); |
||||
|
||||
// some minimum target reached
|
||||
if f.lamports_per_signature == last_lamports_per_signature { |
||||
break; |
||||
} |
||||
|
||||
// shouldn't take more than 1000 steps to get to minimum
|
||||
assert!(count < 1000); |
||||
count += 1; |
||||
} |
||||
|
||||
// Arrive at target rate
|
||||
let mut count = 0; |
||||
while f.lamports_per_signature != f.target_lamports_per_signature { |
||||
f = FeeRateGovernor::new_derived(&f, f.target_signatures_per_slot); |
||||
info!( |
||||
"[target] f.lamports_per_signature={}", |
||||
f.lamports_per_signature |
||||
); |
||||
// shouldn't take more than 100 steps to get to target
|
||||
assert!(count < 100); |
||||
count += 1; |
||||
} |
||||
} |
||||
} |
||||
*/ |
@ -1,101 +0,0 @@ |
||||
[package] |
||||
name = "solana-sdk" |
||||
version = "1.14.13" |
||||
description = "Solana SDK" |
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"] |
||||
repository = "https://github.com/solana-labs/solana" |
||||
homepage = "https://solana.com/" |
||||
documentation = "https://docs.rs/solana-sdk" |
||||
readme = "README.md" |
||||
license = "Apache-2.0" |
||||
edition = "2021" |
||||
|
||||
[features] |
||||
# "program" feature is a legacy feature retained to support v1.3 and older |
||||
# programs. New development should not use this feature. Instead use the |
||||
# solana-program crate |
||||
program = [] |
||||
|
||||
default = [ |
||||
"full" # functionality that is not compatible or needed for on-chain programs |
||||
] |
||||
full = [ |
||||
"assert_matches", |
||||
"byteorder", |
||||
"chrono", |
||||
"generic-array", |
||||
"memmap2", |
||||
"rand", |
||||
"rand_chacha", |
||||
"serde_json", |
||||
# "ed25519-dalek", |
||||
"ed25519-dalek-bip32", |
||||
# "solana-logger", |
||||
"libsecp256k1", |
||||
"sha3", |
||||
"digest", |
||||
] |
||||
|
||||
[dependencies] |
||||
assert_matches = { version = "1.5.0", optional = true } |
||||
base64 = "0.13" |
||||
bincode = "1.3.3" |
||||
bitflags = "1.3.1" |
||||
borsh = "0.9.3" |
||||
bs58 = "0.4.0" |
||||
bytemuck = { version = "1.11.0", features = ["derive"] } |
||||
byteorder = { version = "1.4.3", optional = true } |
||||
chrono = { default-features = false, features = ["alloc"], version = "0.4", optional = true } |
||||
derivation-path = { version = "0.2.0", default-features = false } |
||||
digest = { version = "0.10.1", optional = true } |
||||
ed25519-dalek-bip32 = { version = "0.2.0", optional = true } |
||||
ed25519-dalek = { version = "=1.0.1", git = "https://github.com/Eclipse-Laboratories-Inc/ed25519-dalek", branch = "steven/fix-deps" } |
||||
generic-array = { version = "0.14.5", default-features = false, features = ["serde", "more_lengths"], optional = true } |
||||
hmac = "0.12.1" |
||||
itertools = "0.10.3" |
||||
lazy_static = "1.4.0" |
||||
libsecp256k1 = { version = "0.6.0", optional = true } |
||||
log = "0.4.17" |
||||
memmap2 = { version = "0.5.3", optional = true } |
||||
num-derive = "0.3" |
||||
num-traits = "0.2" |
||||
pbkdf2 = { version = "0.11.0", default-features = false } |
||||
qstring = "0.7.2" |
||||
rand = { version = "0.7.0", optional = true } |
||||
rand_chacha = { version = "0.2.2", optional = true } |
||||
rustversion = "1.0.7" |
||||
serde = "1.0.138" |
||||
serde_bytes = "0.11" |
||||
serde_derive = "1.0.103" |
||||
serde_json = { version = "1.0.81", optional = true } |
||||
sha2 = "0.10.2" |
||||
sha3 = { version = "0.10.1", optional = true } |
||||
# solana-frozen-abi = { path = "../frozen-abi", version = "=1.14.13" } |
||||
# solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.14.13" } |
||||
# solana-logger = { path = "../logger", version = "=1.14.13", optional = true } |
||||
# solana-program = { path = "program", version = "=1.14.13" } |
||||
solana-sdk-macro = { path = "macro", version = "=1.14.13" } |
||||
thiserror = "1.0" |
||||
uriparse = "0.6.4" |
||||
wasm-bindgen = "0.2" |
||||
|
||||
[dependencies.curve25519-dalek] |
||||
version = "3.2.1" |
||||
features = ["serde"] |
||||
git = "https://github.com/Eclipse-Laboratories-Inc/curve25519-dalek" |
||||
branch = "steven/fix-deps" |
||||
|
||||
[dev-dependencies] |
||||
anyhow = "1.0.58" |
||||
hex = "0.4.3" |
||||
static_assertions = "1.1.0" |
||||
tiny-bip39 = "0.8.2" |
||||
|
||||
[build-dependencies] |
||||
rustc_version = "0.4" |
||||
|
||||
[package.metadata.docs.rs] |
||||
targets = ["x86_64-unknown-linux-gnu"] |
||||
|
||||
[lib] |
||||
crate-type = ["cdylib", "rlib"] |
@ -1,23 +0,0 @@ |
||||
[package] |
||||
name = "solana-sdk-macro" |
||||
version = "1.14.13" |
||||
description = "Solana SDK Macro" |
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"] |
||||
repository = "https://github.com/solana-labs/solana" |
||||
homepage = "https://solana.com/" |
||||
documentation = "https://docs.rs/solana-sdk-macro" |
||||
license = "Apache-2.0" |
||||
edition = "2021" |
||||
|
||||
[lib] |
||||
proc-macro = true |
||||
|
||||
[dependencies] |
||||
bs58 = "0.4.0" |
||||
proc-macro2 = "1.0.19" |
||||
quote = "1.0" |
||||
syn = { version = "1.0", features = ["full", "extra-traits"] } |
||||
rustversion = "1.0.7" |
||||
|
||||
[package.metadata.docs.rs] |
||||
targets = ["x86_64-unknown-linux-gnu"] |
@ -1,405 +0,0 @@ |
||||
//! Convenience macro to declare a static public key and functions to interact with it
|
||||
//!
|
||||
//! Input: a single literal base58 string representation of a program's id
|
||||
extern crate proc_macro; |
||||
|
||||
use proc_macro::TokenStream; |
||||
use proc_macro2::{Delimiter, Span, TokenTree}; |
||||
use quote::{quote, ToTokens}; |
||||
use syn::parse::{Parse, ParseStream, Result}; |
||||
use syn::{parse_macro_input, Expr, LitByte, LitStr}; |
||||
|
||||
fn parse_id( |
||||
input: ParseStream, |
||||
pubkey_type: proc_macro2::TokenStream, |
||||
) -> Result<proc_macro2::TokenStream> { |
||||
let id = if input.peek(syn::LitStr) { |
||||
let id_literal: LitStr = input.parse()?; |
||||
parse_pubkey(&id_literal, &pubkey_type)? |
||||
} else { |
||||
let expr: Expr = input.parse()?; |
||||
quote! { #expr } |
||||
}; |
||||
|
||||
if !input.is_empty() { |
||||
let stream: proc_macro2::TokenStream = input.parse()?; |
||||
return Err(syn::Error::new_spanned(stream, "unexpected token")); |
||||
} |
||||
Ok(id) |
||||
} |
||||
|
||||
fn id_to_tokens( |
||||
id: &proc_macro2::TokenStream, |
||||
pubkey_type: proc_macro2::TokenStream, |
||||
tokens: &mut proc_macro2::TokenStream, |
||||
) { |
||||
tokens.extend(quote! { |
||||
/// The static program ID
|
||||
pub static ID: #pubkey_type = #id; |
||||
|
||||
/// Confirms that a given pubkey is equivalent to the program ID
|
||||
pub fn check_id(id: &#pubkey_type) -> bool { |
||||
id == &ID |
||||
} |
||||
|
||||
/// Returns the program ID
|
||||
pub fn id() -> #pubkey_type { |
||||
ID |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
#[test] |
||||
fn test_id() { |
||||
assert!(check_id(&id())); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/* |
||||
fn deprecated_id_to_tokens( |
||||
id: &proc_macro2::TokenStream, |
||||
pubkey_type: proc_macro2::TokenStream, |
||||
tokens: &mut proc_macro2::TokenStream, |
||||
) { |
||||
tokens.extend(quote! { |
||||
/// The static program ID
|
||||
pub static ID: #pubkey_type = #id; |
||||
|
||||
/// Confirms that a given pubkey is equivalent to the program ID
|
||||
#[deprecated()] |
||||
pub fn check_id(id: &#pubkey_type) -> bool { |
||||
id == &ID |
||||
} |
||||
|
||||
/// Returns the program ID
|
||||
#[deprecated()] |
||||
pub fn id() -> #pubkey_type { |
||||
ID |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
#[test] |
||||
fn test_id() { |
||||
#[allow(deprecated)] |
||||
assert!(check_id(&id())); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
struct SdkPubkey(proc_macro2::TokenStream); |
||||
|
||||
impl Parse for SdkPubkey { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { ::solana_sdk::pubkey::Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for SdkPubkey { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
let id = &self.0; |
||||
tokens.extend(quote! {#id}) |
||||
} |
||||
} |
||||
|
||||
struct ProgramSdkPubkey(proc_macro2::TokenStream); |
||||
|
||||
impl Parse for ProgramSdkPubkey { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { ::solana_program::pubkey::Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for ProgramSdkPubkey { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
let id = &self.0; |
||||
tokens.extend(quote! {#id}) |
||||
} |
||||
} |
||||
*/ |
||||
|
||||
struct Id(proc_macro2::TokenStream); |
||||
|
||||
impl Parse for Id { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for Id { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
id_to_tokens(&self.0, quote! { Pubkey }, tokens) |
||||
} |
||||
} |
||||
|
||||
/* |
||||
struct IdDeprecated(proc_macro2::TokenStream); |
||||
|
||||
impl Parse for IdDeprecated { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { ::solana_sdk::pubkey::Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for IdDeprecated { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
deprecated_id_to_tokens(&self.0, quote! { ::solana_sdk::pubkey::Pubkey }, tokens) |
||||
} |
||||
} |
||||
|
||||
struct ProgramSdkId(proc_macro2::TokenStream); |
||||
impl Parse for ProgramSdkId { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { ::solana_program::pubkey::Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for ProgramSdkId { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
id_to_tokens(&self.0, quote! { ::solana_program::pubkey::Pubkey }, tokens) |
||||
} |
||||
} |
||||
|
||||
struct ProgramSdkIdDeprecated(proc_macro2::TokenStream); |
||||
impl Parse for ProgramSdkIdDeprecated { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { ::solana_program::pubkey::Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for ProgramSdkIdDeprecated { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
deprecated_id_to_tokens(&self.0, quote! { ::solana_program::pubkey::Pubkey }, tokens) |
||||
} |
||||
} |
||||
|
||||
#[allow(dead_code)] // `respan` may be compiled out
|
||||
struct RespanInput { |
||||
to_respan: Path, |
||||
respan_using: Span, |
||||
} |
||||
|
||||
impl Parse for RespanInput { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
let to_respan: Path = input.parse()?; |
||||
let _comma: Token![,] = input.parse()?; |
||||
let respan_tree: TokenTree = input.parse()?; |
||||
match respan_tree { |
||||
TokenTree::Group(g) if g.delimiter() == Delimiter::None => { |
||||
let ident: Ident = syn::parse2(g.stream())?; |
||||
Ok(RespanInput { |
||||
to_respan, |
||||
respan_using: ident.span(), |
||||
}) |
||||
} |
||||
TokenTree::Ident(i) => Ok(RespanInput { |
||||
to_respan, |
||||
respan_using: i.span(), |
||||
}), |
||||
val => Err(syn::Error::new_spanned( |
||||
val, |
||||
"expected None-delimited group", |
||||
)), |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// A proc-macro which respans the tokens in its first argument (a `Path`)
|
||||
/// to be resolved at the tokens of its second argument.
|
||||
/// For internal use only.
|
||||
///
|
||||
/// There must be exactly one comma in the input,
|
||||
/// which is used to separate the two arguments.
|
||||
/// The second argument should be exactly one token.
|
||||
///
|
||||
/// For example, `respan!($crate::foo, with_span)`
|
||||
/// produces the tokens `$crate::foo`, but resolved
|
||||
/// at the span of `with_span`.
|
||||
///
|
||||
/// The input to this function should be very short -
|
||||
/// its only purpose is to override the span of a token
|
||||
/// sequence containing `$crate`. For all other purposes,
|
||||
/// a more general proc-macro should be used.
|
||||
#[rustversion::since(1.46.0)] // `Span::resolved_at` is stable in 1.46.0 and above
|
||||
#[proc_macro] |
||||
pub fn respan(input: TokenStream) -> TokenStream { |
||||
// Obtain the `Path` we are going to respan, and the ident
|
||||
// whose span we will be using.
|
||||
let RespanInput { |
||||
to_respan, |
||||
respan_using, |
||||
} = parse_macro_input!(input as RespanInput); |
||||
// Respan all of the tokens in the `Path`
|
||||
let to_respan: proc_macro2::TokenStream = to_respan |
||||
.into_token_stream() |
||||
.into_iter() |
||||
.map(|mut t| { |
||||
// Combine the location of the token with the resolution behavior of `respan_using`
|
||||
let new_span: Span = t.span().resolved_at(respan_using); |
||||
t.set_span(new_span); |
||||
t |
||||
}) |
||||
.collect(); |
||||
TokenStream::from(to_respan) |
||||
} |
||||
|
||||
#[proc_macro] |
||||
pub fn pubkey(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as SdkPubkey); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
|
||||
#[proc_macro] |
||||
pub fn program_pubkey(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as ProgramSdkPubkey); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
*/ |
||||
|
||||
#[proc_macro] |
||||
pub fn declare_id(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as Id); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
|
||||
/* |
||||
#[proc_macro] |
||||
pub fn declare_deprecated_id(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as IdDeprecated); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
|
||||
#[proc_macro] |
||||
pub fn program_declare_id(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as ProgramSdkId); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
|
||||
#[proc_macro] |
||||
pub fn program_declare_deprecated_id(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as ProgramSdkIdDeprecated); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
*/ |
||||
|
||||
fn parse_pubkey( |
||||
id_literal: &LitStr, |
||||
pubkey_type: &proc_macro2::TokenStream, |
||||
) -> Result<proc_macro2::TokenStream> { |
||||
let id_vec = bs58::decode(id_literal.value()) |
||||
.into_vec() |
||||
.map_err(|_| syn::Error::new_spanned(id_literal, "failed to decode base58 string"))?; |
||||
let id_array = <[u8; 32]>::try_from(<&[u8]>::clone(&&id_vec[..])).map_err(|_| { |
||||
syn::Error::new_spanned( |
||||
id_literal, |
||||
format!("pubkey array is not 32 bytes long: len={}", id_vec.len()), |
||||
) |
||||
})?; |
||||
let bytes = id_array.iter().map(|b| LitByte::new(*b, Span::call_site())); |
||||
Ok(quote! { |
||||
#pubkey_type::new_from_array( |
||||
[#(#bytes,)*] |
||||
) |
||||
}) |
||||
} |
||||
|
||||
/* |
||||
struct Pubkeys { |
||||
method: Ident, |
||||
num: usize, |
||||
pubkeys: proc_macro2::TokenStream, |
||||
} |
||||
impl Parse for Pubkeys { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
let pubkey_type = quote! { |
||||
::solana_sdk::pubkey::Pubkey |
||||
}; |
||||
|
||||
let method = input.parse()?; |
||||
let _comma: Token![,] = input.parse()?; |
||||
let (num, pubkeys) = if input.peek(syn::LitStr) { |
||||
let id_literal: LitStr = input.parse()?; |
||||
(1, parse_pubkey(&id_literal, &pubkey_type)?) |
||||
} else if input.peek(Bracket) { |
||||
let pubkey_strings; |
||||
bracketed!(pubkey_strings in input); |
||||
let punctuated: Punctuated<LitStr, Token![,]> = |
||||
Punctuated::parse_terminated(&pubkey_strings)?; |
||||
let mut pubkeys: Punctuated<proc_macro2::TokenStream, Token![,]> = Punctuated::new(); |
||||
for string in punctuated.iter() { |
||||
pubkeys.push(parse_pubkey(string, &pubkey_type)?); |
||||
} |
||||
(pubkeys.len(), quote! {#pubkeys}) |
||||
} else { |
||||
let stream: proc_macro2::TokenStream = input.parse()?; |
||||
return Err(syn::Error::new_spanned(stream, "unexpected token")); |
||||
}; |
||||
|
||||
Ok(Pubkeys { |
||||
method, |
||||
num, |
||||
pubkeys, |
||||
}) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for Pubkeys { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
let Pubkeys { |
||||
method, |
||||
num, |
||||
pubkeys, |
||||
} = self; |
||||
|
||||
let pubkey_type = quote! { |
||||
::solana_sdk::pubkey::Pubkey |
||||
}; |
||||
if *num == 1 { |
||||
tokens.extend(quote! { |
||||
pub fn #method() -> #pubkey_type { |
||||
#pubkeys |
||||
} |
||||
}); |
||||
} else { |
||||
tokens.extend(quote! { |
||||
pub fn #method() -> ::std::vec::Vec<#pubkey_type> { |
||||
vec![#pubkeys] |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
|
||||
#[proc_macro] |
||||
pub fn pubkeys(input: TokenStream) -> TokenStream { |
||||
let pubkeys = parse_macro_input!(input as Pubkeys); |
||||
TokenStream::from(quote! {#pubkeys}) |
||||
} |
||||
|
||||
// The normal `wasm_bindgen` macro generates a .bss section which causes the resulting
|
||||
// BPF program to fail to load, so for now this stub should be used when building for BPF
|
||||
#[proc_macro_attribute] |
||||
pub fn wasm_bindgen_stub(_attr: TokenStream, item: TokenStream) -> TokenStream { |
||||
match parse_macro_input!(item as syn::Item) { |
||||
syn::Item::Struct(mut item_struct) => { |
||||
if let syn::Fields::Named(fields) = &mut item_struct.fields { |
||||
// Strip out any `#[wasm_bindgen]` added to struct fields. This is custom
|
||||
// syntax supplied by the normal `wasm_bindgen` macro.
|
||||
for field in fields.named.iter_mut() { |
||||
field.attrs.retain(|attr| { |
||||
!attr |
||||
.path |
||||
.segments |
||||
.iter() |
||||
.any(|segment| segment.ident == "wasm_bindgen") |
||||
}); |
||||
} |
||||
} |
||||
quote! { #item_struct } |
||||
} |
||||
item => { |
||||
quote!(#item) |
||||
} |
||||
} |
||||
.into() |
||||
} |
||||
*/ |
@ -1 +0,0 @@ |
||||
pub use solana_sdk_macro::declare_id; |
@ -1,12 +0,0 @@ |
||||
//! The [secp256k1 native program][np].
|
||||
//!
|
||||
//! [np]: https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program
|
||||
//!
|
||||
//! Constructors for secp256k1 program instructions, and documentation on the
|
||||
//! program's usage can be found in [`solana_sdk::secp256k1_instruction`].
|
||||
//!
|
||||
//! [`solana_sdk::secp256k1_instruction`]: https://docs.rs/solana-sdk/latest/solana_sdk/secp256k1_instruction/index.html
|
||||
use crate::solana::pubkey::Pubkey; |
||||
use solana_sdk_macro::declare_id; |
||||
|
||||
declare_id!("KeccakSecp256k11111111111111111111111111111"); |
@ -1 +0,0 @@ |
||||
pub use solana_sdk_macro::declare_id; |
@ -1,423 +0,0 @@ |
||||
//! Convenience macro to declare a static public key and functions to interact with it
|
||||
//!
|
||||
//! Input: a single literal base58 string representation of a program's id
|
||||
extern crate proc_macro; |
||||
|
||||
use proc_macro::{TokenStream}; |
||||
use syn::{parse_macro_input, LitStr, Expr, LitByte}; |
||||
use quote::{quote, ToTokens}; |
||||
use syn::parse::{Parse, ParseStream, Result}; |
||||
use proc_macro2::{Delimiter, Span, TokenTree}; |
||||
|
||||
|
||||
use { |
||||
// proc_macro::TokenStream,
|
||||
// proc_macro2::{Delimiter, Span, TokenTree},
|
||||
// quote::{quote, ToTokens},
|
||||
// std::convert::TryFrom,
|
||||
// syn::{
|
||||
// bracketed,
|
||||
// parse::{Parse, ParseStream, Result},
|
||||
// parse_macro_input,
|
||||
// punctuated::Punctuated,
|
||||
// token::Bracket,
|
||||
// Expr, Ident, LitByte, LitStr, Path, Token,
|
||||
// },
|
||||
}; |
||||
|
||||
|
||||
fn parse_id( |
||||
input: ParseStream, |
||||
pubkey_type: proc_macro2::TokenStream, |
||||
) -> Result<proc_macro2::TokenStream> { |
||||
let id = if input.peek(syn::LitStr) { |
||||
let id_literal: LitStr = input.parse()?; |
||||
parse_pubkey(&id_literal, &pubkey_type)? |
||||
} else { |
||||
let expr: Expr = input.parse()?; |
||||
quote! { #expr } |
||||
}; |
||||
|
||||
if !input.is_empty() { |
||||
let stream: proc_macro2::TokenStream = input.parse()?; |
||||
return Err(syn::Error::new_spanned(stream, "unexpected token")); |
||||
} |
||||
Ok(id) |
||||
} |
||||
|
||||
fn id_to_tokens( |
||||
id: &proc_macro2::TokenStream, |
||||
pubkey_type: proc_macro2::TokenStream, |
||||
tokens: &mut proc_macro2::TokenStream, |
||||
) { |
||||
tokens.extend(quote! { |
||||
/// The static program ID
|
||||
pub static ID: #pubkey_type = #id; |
||||
|
||||
/// Confirms that a given pubkey is equivalent to the program ID
|
||||
pub fn check_id(id: &#pubkey_type) -> bool { |
||||
id == &ID |
||||
} |
||||
|
||||
/// Returns the program ID
|
||||
pub fn id() -> #pubkey_type { |
||||
ID |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
#[test] |
||||
fn test_id() { |
||||
assert!(check_id(&id())); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/* |
||||
fn deprecated_id_to_tokens( |
||||
id: &proc_macro2::TokenStream, |
||||
pubkey_type: proc_macro2::TokenStream, |
||||
tokens: &mut proc_macro2::TokenStream, |
||||
) { |
||||
tokens.extend(quote! { |
||||
/// The static program ID
|
||||
pub static ID: #pubkey_type = #id; |
||||
|
||||
/// Confirms that a given pubkey is equivalent to the program ID
|
||||
#[deprecated()] |
||||
pub fn check_id(id: &#pubkey_type) -> bool { |
||||
id == &ID |
||||
} |
||||
|
||||
/// Returns the program ID
|
||||
#[deprecated()] |
||||
pub fn id() -> #pubkey_type { |
||||
ID |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
#[test] |
||||
fn test_id() { |
||||
#[allow(deprecated)] |
||||
assert!(check_id(&id())); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
struct SdkPubkey(proc_macro2::TokenStream); |
||||
|
||||
impl Parse for SdkPubkey { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { ::solana_sdk::pubkey::Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for SdkPubkey { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
let id = &self.0; |
||||
tokens.extend(quote! {#id}) |
||||
} |
||||
} |
||||
|
||||
struct ProgramSdkPubkey(proc_macro2::TokenStream); |
||||
|
||||
impl Parse for ProgramSdkPubkey { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { ::solana_program::pubkey::Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for ProgramSdkPubkey { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
let id = &self.0; |
||||
tokens.extend(quote! {#id}) |
||||
} |
||||
} |
||||
*/ |
||||
|
||||
struct Id(proc_macro2::TokenStream); |
||||
|
||||
|
||||
impl Parse for Id { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { ::solana_sdk::pubkey::Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for Id { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
id_to_tokens(&self.0, quote! { ::solana_sdk::pubkey::Pubkey }, tokens) |
||||
} |
||||
} |
||||
|
||||
/* |
||||
struct IdDeprecated(proc_macro2::TokenStream); |
||||
|
||||
impl Parse for IdDeprecated { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { ::solana_sdk::pubkey::Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for IdDeprecated { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
deprecated_id_to_tokens(&self.0, quote! { ::solana_sdk::pubkey::Pubkey }, tokens) |
||||
} |
||||
} |
||||
|
||||
struct ProgramSdkId(proc_macro2::TokenStream); |
||||
impl Parse for ProgramSdkId { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { ::solana_program::pubkey::Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for ProgramSdkId { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
id_to_tokens(&self.0, quote! { ::solana_program::pubkey::Pubkey }, tokens) |
||||
} |
||||
} |
||||
|
||||
struct ProgramSdkIdDeprecated(proc_macro2::TokenStream); |
||||
impl Parse for ProgramSdkIdDeprecated { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
parse_id(input, quote! { ::solana_program::pubkey::Pubkey }).map(Self) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for ProgramSdkIdDeprecated { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
deprecated_id_to_tokens(&self.0, quote! { ::solana_program::pubkey::Pubkey }, tokens) |
||||
} |
||||
} |
||||
|
||||
#[allow(dead_code)] // `respan` may be compiled out
|
||||
struct RespanInput { |
||||
to_respan: Path, |
||||
respan_using: Span, |
||||
} |
||||
|
||||
impl Parse for RespanInput { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
let to_respan: Path = input.parse()?; |
||||
let _comma: Token![,] = input.parse()?; |
||||
let respan_tree: TokenTree = input.parse()?; |
||||
match respan_tree { |
||||
TokenTree::Group(g) if g.delimiter() == Delimiter::None => { |
||||
let ident: Ident = syn::parse2(g.stream())?; |
||||
Ok(RespanInput { |
||||
to_respan, |
||||
respan_using: ident.span(), |
||||
}) |
||||
} |
||||
TokenTree::Ident(i) => Ok(RespanInput { |
||||
to_respan, |
||||
respan_using: i.span(), |
||||
}), |
||||
val => Err(syn::Error::new_spanned( |
||||
val, |
||||
"expected None-delimited group", |
||||
)), |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// A proc-macro which respans the tokens in its first argument (a `Path`)
|
||||
/// to be resolved at the tokens of its second argument.
|
||||
/// For internal use only.
|
||||
///
|
||||
/// There must be exactly one comma in the input,
|
||||
/// which is used to separate the two arguments.
|
||||
/// The second argument should be exactly one token.
|
||||
///
|
||||
/// For example, `respan!($crate::foo, with_span)`
|
||||
/// produces the tokens `$crate::foo`, but resolved
|
||||
/// at the span of `with_span`.
|
||||
///
|
||||
/// The input to this function should be very short -
|
||||
/// its only purpose is to override the span of a token
|
||||
/// sequence containing `$crate`. For all other purposes,
|
||||
/// a more general proc-macro should be used.
|
||||
#[rustversion::since(1.46.0)] // `Span::resolved_at` is stable in 1.46.0 and above
|
||||
#[proc_macro] |
||||
pub fn respan(input: TokenStream) -> TokenStream { |
||||
// Obtain the `Path` we are going to respan, and the ident
|
||||
// whose span we will be using.
|
||||
let RespanInput { |
||||
to_respan, |
||||
respan_using, |
||||
} = parse_macro_input!(input as RespanInput); |
||||
// Respan all of the tokens in the `Path`
|
||||
let to_respan: proc_macro2::TokenStream = to_respan |
||||
.into_token_stream() |
||||
.into_iter() |
||||
.map(|mut t| { |
||||
// Combine the location of the token with the resolution behavior of `respan_using`
|
||||
let new_span: Span = t.span().resolved_at(respan_using); |
||||
t.set_span(new_span); |
||||
t |
||||
}) |
||||
.collect(); |
||||
TokenStream::from(to_respan) |
||||
} |
||||
|
||||
#[proc_macro] |
||||
pub fn pubkey(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as SdkPubkey); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
|
||||
#[proc_macro] |
||||
pub fn program_pubkey(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as ProgramSdkPubkey); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
*/ |
||||
|
||||
#[proc_macro] |
||||
pub fn declare_id(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as Id); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
|
||||
/* |
||||
#[proc_macro] |
||||
pub fn declare_deprecated_id(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as IdDeprecated); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
|
||||
#[proc_macro] |
||||
pub fn program_declare_id(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as ProgramSdkId); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
|
||||
#[proc_macro] |
||||
pub fn program_declare_deprecated_id(input: TokenStream) -> TokenStream { |
||||
let id = parse_macro_input!(input as ProgramSdkIdDeprecated); |
||||
TokenStream::from(quote! {#id}) |
||||
} |
||||
*/ |
||||
|
||||
fn parse_pubkey( |
||||
id_literal: &LitStr, |
||||
pubkey_type: &proc_macro2::TokenStream, |
||||
) -> Result<proc_macro2::TokenStream> { |
||||
let id_vec = bs58::decode(id_literal.value()) |
||||
.into_vec() |
||||
.map_err(|_| syn::Error::new_spanned(id_literal, "failed to decode base58 string"))?; |
||||
let id_array = <[u8; 32]>::try_from(<&[u8]>::clone(&&id_vec[..])).map_err(|_| { |
||||
syn::Error::new_spanned( |
||||
id_literal, |
||||
format!("pubkey array is not 32 bytes long: len={}", id_vec.len()), |
||||
) |
||||
})?; |
||||
let bytes = id_array.iter().map(|b| LitByte::new(*b, Span::call_site())); |
||||
Ok(quote! { |
||||
#pubkey_type::new_from_array( |
||||
[#(#bytes,)*] |
||||
) |
||||
}) |
||||
} |
||||
|
||||
/* |
||||
struct Pubkeys { |
||||
method: Ident, |
||||
num: usize, |
||||
pubkeys: proc_macro2::TokenStream, |
||||
} |
||||
impl Parse for Pubkeys { |
||||
fn parse(input: ParseStream) -> Result<Self> { |
||||
let pubkey_type = quote! { |
||||
::solana_sdk::pubkey::Pubkey |
||||
}; |
||||
|
||||
let method = input.parse()?; |
||||
let _comma: Token![,] = input.parse()?; |
||||
let (num, pubkeys) = if input.peek(syn::LitStr) { |
||||
let id_literal: LitStr = input.parse()?; |
||||
(1, parse_pubkey(&id_literal, &pubkey_type)?) |
||||
} else if input.peek(Bracket) { |
||||
let pubkey_strings; |
||||
bracketed!(pubkey_strings in input); |
||||
let punctuated: Punctuated<LitStr, Token![,]> = |
||||
Punctuated::parse_terminated(&pubkey_strings)?; |
||||
let mut pubkeys: Punctuated<proc_macro2::TokenStream, Token![,]> = Punctuated::new(); |
||||
for string in punctuated.iter() { |
||||
pubkeys.push(parse_pubkey(string, &pubkey_type)?); |
||||
} |
||||
(pubkeys.len(), quote! {#pubkeys}) |
||||
} else { |
||||
let stream: proc_macro2::TokenStream = input.parse()?; |
||||
return Err(syn::Error::new_spanned(stream, "unexpected token")); |
||||
}; |
||||
|
||||
Ok(Pubkeys { |
||||
method, |
||||
num, |
||||
pubkeys, |
||||
}) |
||||
} |
||||
} |
||||
|
||||
impl ToTokens for Pubkeys { |
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
||||
let Pubkeys { |
||||
method, |
||||
num, |
||||
pubkeys, |
||||
} = self; |
||||
|
||||
let pubkey_type = quote! { |
||||
::solana_sdk::pubkey::Pubkey |
||||
}; |
||||
if *num == 1 { |
||||
tokens.extend(quote! { |
||||
pub fn #method() -> #pubkey_type { |
||||
#pubkeys |
||||
} |
||||
}); |
||||
} else { |
||||
tokens.extend(quote! { |
||||
pub fn #method() -> ::std::vec::Vec<#pubkey_type> { |
||||
vec![#pubkeys] |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
|
||||
#[proc_macro] |
||||
pub fn pubkeys(input: TokenStream) -> TokenStream { |
||||
let pubkeys = parse_macro_input!(input as Pubkeys); |
||||
TokenStream::from(quote! {#pubkeys}) |
||||
} |
||||
|
||||
// The normal `wasm_bindgen` macro generates a .bss section which causes the resulting
|
||||
// BPF program to fail to load, so for now this stub should be used when building for BPF
|
||||
#[proc_macro_attribute] |
||||
pub fn wasm_bindgen_stub(_attr: TokenStream, item: TokenStream) -> TokenStream { |
||||
match parse_macro_input!(item as syn::Item) { |
||||
syn::Item::Struct(mut item_struct) => { |
||||
if let syn::Fields::Named(fields) = &mut item_struct.fields { |
||||
// Strip out any `#[wasm_bindgen]` added to struct fields. This is custom
|
||||
// syntax supplied by the normal `wasm_bindgen` macro.
|
||||
for field in fields.named.iter_mut() { |
||||
field.attrs.retain(|attr| { |
||||
!attr |
||||
.path |
||||
.segments |
||||
.iter() |
||||
.any(|segment| segment.ident == "wasm_bindgen") |
||||
}); |
||||
} |
||||
} |
||||
quote! { #item_struct } |
||||
} |
||||
item => { |
||||
quote!(#item) |
||||
} |
||||
} |
||||
.into() |
||||
} |
||||
*/ |
Loading…
Reference in new issue