diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 0bb1317dc7f965..33d7bd28bb5e30 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -85,11 +85,11 @@ solana-program = { workspace = true } solana-sdk-macro = { workspace = true } thiserror = { workspace = true } uriparse = { workspace = true } -wasm-bindgen = { workspace = true } [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.1", features = ["wasm-bindgen"] } js-sys = { workspace = true } +wasm-bindgen = { workspace = true } [dev-dependencies] anyhow = { workspace = true } diff --git a/sdk/macro/src/lib.rs b/sdk/macro/src/lib.rs index 73121b568003cd..9808fad0ccd08a 100644 --- a/sdk/macro/src/lib.rs +++ b/sdk/macro/src/lib.rs @@ -378,34 +378,6 @@ pub fn pubkeys(input: TokenStream) -> TokenStream { TokenStream::from(quote! {#pubkeys}) } -// The normal `wasm_bindgen` macro generates a .bss section which causes the resulting -// SBF program to fail to load, so for now this stub should be used when building for SBF -#[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() -} - // Sets padding in structures to zero explicitly. // Otherwise padding could be inconsistent across the network and lead to divergence / consensus failures. #[proc_macro_derive(CloneZeroed)] diff --git a/sdk/program/Cargo.toml b/sdk/program/Cargo.toml index 3c03bc21deaead..e2f5085ac0d0bf 100644 --- a/sdk/program/Cargo.toml +++ b/sdk/program/Cargo.toml @@ -57,7 +57,6 @@ itertools = { workspace = true } libsecp256k1 = { workspace = true } num-bigint = { workspace = true } rand = { workspace = true } -wasm-bindgen = { workspace = true } [target.'cfg(not(target_os = "solana"))'.dev-dependencies] arbitrary = { workspace = true, features = ["derive"] } @@ -69,6 +68,7 @@ console_error_panic_hook = { workspace = true } console_log = { workspace = true } getrandom = { workspace = true, features = ["js", "wasm-bindgen"] } js-sys = { workspace = true } +wasm-bindgen = { workspace = true } [target.'cfg(not(target_pointer_width = "64"))'.dependencies] parking_lot = { workspace = true } diff --git a/sdk/program/src/hash.rs b/sdk/program/src/hash.rs index 6652c37001cb1a..94fb7df9367dc2 100644 --- a/sdk/program/src/hash.rs +++ b/sdk/program/src/hash.rs @@ -3,10 +3,12 @@ //! [SHA-256]: https://en.wikipedia.org/wiki/SHA-2 //! [`Hash`]: struct@Hash +#[cfg(target_arch = "wasm32")] +use crate::wasm_bindgen; #[cfg(feature = "borsh")] use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use { - crate::{sanitize::Sanitize, wasm_bindgen}, + crate::sanitize::Sanitize, bytemuck::{Pod, Zeroable}, sha2::{Digest, Sha256}, std::{convert::TryFrom, fmt, mem, str::FromStr}, @@ -28,7 +30,7 @@ const MAX_BASE58_LEN: usize = 44; /// [blake3]: https://github.com/BLAKE3-team/BLAKE3 /// [`blake3`]: crate::blake3 /// [`Message::hash`]: crate::message::Message::hash -#[wasm_bindgen] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen)] #[cfg_attr(feature = "frozen-abi", derive(AbiExample))] #[cfg_attr( feature = "borsh", diff --git a/sdk/program/src/instruction.rs b/sdk/program/src/instruction.rs index 19be50d9b693b9..b3bba2c2fcfd35 100644 --- a/sdk/program/src/instruction.rs +++ b/sdk/program/src/instruction.rs @@ -13,10 +13,12 @@ #![allow(clippy::arithmetic_side_effects)] +#[cfg(target_arch = "wasm32")] +use crate::wasm_bindgen; #[cfg(feature = "borsh")] use borsh::BorshSerialize; use { - crate::{pubkey::Pubkey, sanitize::Sanitize, short_vec, wasm_bindgen}, + crate::{pubkey::Pubkey, sanitize::Sanitize, short_vec}, bincode::serialize, serde::Serialize, thiserror::Error, @@ -325,16 +327,27 @@ pub enum InstructionError { /// Programs may require signatures from some accounts, in which case they /// should be specified as signers during `Instruction` construction. The /// program must still validate during execution that the account is a signer. -#[wasm_bindgen] +#[cfg(not(target_arch = "wasm32"))] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct Instruction { /// Pubkey of the program that executes this instruction. - #[wasm_bindgen(skip)] pub program_id: Pubkey, /// Metadata describing accounts that should be passed to the program. - #[wasm_bindgen(skip)] pub accounts: Vec, /// Opaque data passed to the program for its own interpretation. + pub data: Vec, +} + +/// wasm-bindgen version of the Instruction struct. +/// This duplication is required until https://github.com/rustwasm/wasm-bindgen/issues/3671 +/// is fixed. This must not diverge from the regular non-wasm Instruction struct. +#[cfg(target_arch = "wasm32")] +#[wasm_bindgen] +pub struct Instruction { + #[wasm_bindgen(skip)] + pub program_id: Pubkey, + #[wasm_bindgen(skip)] + pub accounts: Vec, #[wasm_bindgen(skip)] pub data: Vec, } diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index 017ac3a067744d..1a136da467d887 100644 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -545,12 +545,7 @@ pub mod address_lookup_table_account { pub use crate::address_lookup_table::AddressLookupTableAccount; } -#[cfg(target_os = "solana")] -pub use solana_sdk_macro::wasm_bindgen_stub as wasm_bindgen; -/// Re-export of [wasm-bindgen]. -/// -/// [wasm-bindgen]: https://rustwasm.github.io/docs/wasm-bindgen/ -#[cfg(not(target_os = "solana"))] +#[cfg(target_arch = "wasm32")] pub use wasm_bindgen::prelude::wasm_bindgen; /// The [config native program][np]. diff --git a/sdk/program/src/message/legacy.rs b/sdk/program/src/message/legacy.rs index b9dc518e028ed0..59a8c673f7867d 100644 --- a/sdk/program/src/message/legacy.rs +++ b/sdk/program/src/message/legacy.rs @@ -11,6 +11,8 @@ #![allow(clippy::arithmetic_side_effects)] +#[cfg(target_arch = "wasm32")] +use crate::wasm_bindgen; #[allow(deprecated)] pub use builtins::{BUILTIN_PROGRAMS_KEYS, MAYBE_BUILTIN_KEY_OR_SYSVAR}; use { @@ -21,7 +23,7 @@ use { message::{compiled_keys::CompiledKeys, MessageHeader}, pubkey::Pubkey, sanitize::{Sanitize, SanitizeError}, - short_vec, system_instruction, system_program, sysvar, wasm_bindgen, + short_vec, system_instruction, system_program, sysvar, }, std::{collections::HashSet, convert::TryFrom, str::FromStr}, }; @@ -117,7 +119,7 @@ fn compile_instructions(ixs: &[Instruction], keys: &[Pubkey]) -> Vec Vec, @@ -141,6 +141,33 @@ pub struct Message { /// Programs that will be executed in sequence and committed in one atomic transaction if all /// succeed. + #[serde(with = "short_vec")] + pub instructions: Vec, +} + +/// wasm-bindgen version of the Message struct. +/// This duplication is required until https://github.com/rustwasm/wasm-bindgen/issues/3671 +/// is fixed. This must not diverge from the regular non-wasm Message struct. +#[cfg(target_arch = "wasm32")] +#[wasm_bindgen] +#[cfg_attr( + feature = "frozen-abi", + frozen_abi(digest = "2KnLEqfLcTBQqitE22Pp8JYkaqVVbAkGbCfdeHoyxcAU"), + derive(AbiExample) +)] +#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Message { + #[wasm_bindgen(skip)] + pub header: MessageHeader, + + #[wasm_bindgen(skip)] + #[serde(with = "short_vec")] + pub account_keys: Vec, + + /// The id of a recent ledger entry. + pub recent_blockhash: Hash, + #[wasm_bindgen(skip)] #[serde(with = "short_vec")] pub instructions: Vec, diff --git a/sdk/program/src/pubkey.rs b/sdk/program/src/pubkey.rs index e6763ddbde2640..3db8d88031e9dc 100644 --- a/sdk/program/src/pubkey.rs +++ b/sdk/program/src/pubkey.rs @@ -2,12 +2,14 @@ #![allow(clippy::arithmetic_side_effects)] +#[cfg(target_arch = "wasm32")] +use crate::wasm_bindgen; #[cfg(test)] use arbitrary::Arbitrary; #[cfg(feature = "borsh")] use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use { - crate::{decode_error::DecodeError, hash::hashv, wasm_bindgen}, + crate::{decode_error::DecodeError, hash::hashv}, bytemuck::{Pod, Zeroable}, num_derive::{FromPrimitive, ToPrimitive}, std::{ @@ -68,7 +70,7 @@ impl From for PubkeyError { /// [ed25519]: https://ed25519.cr.yp.to/ /// [pdas]: https://solana.com/docs/core/cpi#program-derived-addresses /// [`Keypair`]: https://docs.rs/solana-sdk/latest/solana_sdk/signer/keypair/struct.Keypair.html -#[wasm_bindgen] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen)] #[repr(transparent)] #[cfg_attr(feature = "frozen-abi", derive(AbiExample))] #[cfg_attr( diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index e6a1f66415c25e..728f63e316b887 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -41,6 +41,8 @@ pub use signer::signers; pub use solana_program::program_stubs; // These solana_program imports could be *-imported, but that causes a bunch of // confusing duplication in the docs due to a rustdoc bug. #26211 +#[cfg(target_arch = "wasm32")] +pub use solana_program::wasm_bindgen; pub use solana_program::{ account_info, address_lookup_table, alt_bn128, big_mod_exp, blake3, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, clock, config, custom_heap_default, @@ -51,7 +53,7 @@ pub use solana_program::{ program_memory, program_option, program_pack, rent, sanitize, secp256k1_program, secp256k1_recover, serde_varint, serialize_utils, short_vec, slot_hashes, slot_history, stable_layout, stake, stake_history, syscalls, system_instruction, system_program, sysvar, - unchecked_div_by_const, vote, wasm_bindgen, + unchecked_div_by_const, vote, }; #[allow(deprecated)] pub use solana_program::{address_lookup_table_account, sdk_ids}; diff --git a/sdk/src/signer/keypair.rs b/sdk/src/signer/keypair.rs index 1873996a399391..9e6088c1b5444f 100644 --- a/sdk/src/signer/keypair.rs +++ b/sdk/src/signer/keypair.rs @@ -1,5 +1,7 @@ #![cfg(feature = "full")] +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::prelude::*; use { crate::{ derivation_path::DerivationPath, @@ -16,11 +18,10 @@ use { io::{Read, Write}, path::Path, }, - wasm_bindgen::prelude::*, }; /// A vanilla Ed25519 key pair -#[wasm_bindgen] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen)] #[derive(Debug)] pub struct Keypair(ed25519_dalek::Keypair); diff --git a/sdk/src/transaction/mod.rs b/sdk/src/transaction/mod.rs index 520a80d0289684..47e4ae95cbfdb5 100644 --- a/sdk/src/transaction/mod.rs +++ b/sdk/src/transaction/mod.rs @@ -111,6 +111,8 @@ #![cfg(feature = "full")] +#[cfg(target_arch = "wasm32")] +use crate::wasm_bindgen; use { crate::{ hash::Hash, @@ -124,7 +126,6 @@ use { short_vec, signature::{Signature, SignerError}, signers::Signers, - wasm_bindgen, }, serde::Serialize, solana_program::{system_instruction::SystemInstruction, system_program}, @@ -167,7 +168,7 @@ pub type Result = result::Result; /// if the caller has knowledge that the first account of the constructed /// transaction's `Message` is both a signer and the expected fee-payer, then /// redundantly specifying the fee-payer is not strictly required. -#[wasm_bindgen] +#[cfg(not(target_arch = "wasm32"))] #[cfg_attr( feature = "frozen-abi", derive(AbiExample), @@ -184,11 +185,29 @@ pub struct Transaction { /// [`MessageHeader`]: crate::message::MessageHeader /// [`num_required_signatures`]: crate::message::MessageHeader::num_required_signatures // NOTE: Serialization-related changes must be paired with the direct read at sigverify. - #[wasm_bindgen(skip)] #[serde(with = "short_vec")] pub signatures: Vec, /// The message to sign. + pub message: Message, +} + +/// wasm-bindgen version of the Transaction struct. +/// This duplication is required until https://github.com/rustwasm/wasm-bindgen/issues/3671 +/// is fixed. This must not diverge from the regular non-wasm Transaction struct. +#[cfg(target_arch = "wasm32")] +#[wasm_bindgen] +#[cfg_attr( + feature = "frozen-abi", + derive(AbiExample), + frozen_abi(digest = "FZtncnS1Xk8ghHfKiXE5oGiUbw2wJhmfXQuNgQR3K6Mc") +)] +#[derive(Debug, PartialEq, Default, Eq, Clone, Serialize, Deserialize)] +pub struct Transaction { + #[wasm_bindgen(skip)] + #[serde(with = "short_vec")] + pub signatures: Vec, + #[wasm_bindgen(skip)] pub message: Message, }