Add wasm bindings for `Pubkey` and `Keypair`
This commit is contained in:
parent
6919c4863b
commit
488dc37fec
|
@ -761,6 +761,26 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494"
|
||||
dependencies = [
|
||||
"log 0.4.14",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const_fn"
|
||||
version = "0.4.8"
|
||||
|
@ -5440,6 +5460,8 @@ dependencies = [
|
|||
"bs58 0.4.0",
|
||||
"bv",
|
||||
"bytemuck",
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
"curve25519-dalek 3.2.0",
|
||||
"itertools 0.10.3",
|
||||
"lazy_static",
|
||||
|
@ -5463,6 +5485,7 @@ dependencies = [
|
|||
"solana-sdk-macro 1.10.0",
|
||||
"static_assertions",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5755,6 +5778,7 @@ dependencies = [
|
|||
"thiserror",
|
||||
"tiny-bip39",
|
||||
"uriparse",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -226,6 +226,19 @@ EOF
|
|||
annotate --style info \
|
||||
"downstream-projects skipped as no relevant files were modified"
|
||||
fi
|
||||
|
||||
# Wasm support
|
||||
if affects \
|
||||
^ci/test-wasm.sh \
|
||||
^ci/test-stable.sh \
|
||||
^sdk/ \
|
||||
; then
|
||||
command_step wasm ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-wasm.sh" 20
|
||||
else
|
||||
annotate --style info \
|
||||
"wasm skipped as no relevant files were modified"
|
||||
fi
|
||||
|
||||
# Benches...
|
||||
if affects \
|
||||
.rs$ \
|
||||
|
|
|
@ -11,6 +11,7 @@ RUN set -x \
|
|||
&& apt-get install apt-transport-https \
|
||||
&& echo deb https://apt.buildkite.com/buildkite-agent stable main > /etc/apt/sources.list.d/buildkite-agent.list \
|
||||
&& apt-key adv --no-tty --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 32A37959C2FA5C3C99EFBC32A79206696452D198 \
|
||||
&& curl -fsSL https://deb.nodesource.com/setup_current.x | bash - \
|
||||
&& apt update \
|
||||
&& apt install -y \
|
||||
buildkite-agent \
|
||||
|
@ -19,6 +20,7 @@ RUN set -x \
|
|||
lcov \
|
||||
libudev-dev \
|
||||
mscgen \
|
||||
nodejs \
|
||||
net-tools \
|
||||
rsync \
|
||||
sudo \
|
||||
|
@ -26,8 +28,11 @@ RUN set -x \
|
|||
unzip \
|
||||
\
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& node --version \
|
||||
&& npm --version \
|
||||
&& rustup component add rustfmt \
|
||||
&& rustup component add clippy \
|
||||
&& rustup target add wasm32-unknown-unknown \
|
||||
&& cargo install cargo-audit \
|
||||
&& cargo install mdbook \
|
||||
&& cargo install mdbook-linkcheck \
|
||||
|
|
|
@ -103,6 +103,19 @@ test-local-cluster)
|
|||
_ "$cargo" stable test --release --package solana-local-cluster ${V:+--verbose} -- --nocapture --test-threads=1
|
||||
exit 0
|
||||
;;
|
||||
test-wasm)
|
||||
_ node --version
|
||||
_ npm --version
|
||||
for dir in sdk/{program,}; do
|
||||
if [[ -r "$dir"/package.json ]]; then
|
||||
pushd "$dir"
|
||||
_ npm install
|
||||
_ npm test
|
||||
popd
|
||||
fi
|
||||
done
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Error: Unknown test: $testName"
|
||||
;;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
test-stable.sh
|
|
@ -458,6 +458,26 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494"
|
||||
dependencies = [
|
||||
"log",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
|
@ -1419,9 +1439,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.49"
|
||||
version = "0.3.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc15e39392125075f60c95ba416f5381ff6c3a948ff02ab12464715adf56c821"
|
||||
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -3270,6 +3290,8 @@ dependencies = [
|
|||
"bs58 0.4.0",
|
||||
"bv",
|
||||
"bytemuck",
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
"curve25519-dalek 3.2.0",
|
||||
"itertools 0.10.3",
|
||||
"lazy_static",
|
||||
|
@ -3291,6 +3313,7 @@ dependencies = [
|
|||
"solana-logger 1.10.0",
|
||||
"solana-sdk-macro 1.10.0",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3454,6 +3477,7 @@ dependencies = [
|
|||
"solana-sdk-macro 1.10.0",
|
||||
"thiserror",
|
||||
"uriparse",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4198,9 +4222,9 @@ checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.72"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fe8f61dba8e5d645a4d8132dc7a0a66861ed5e1045d2c0ed940fab33bac0fbe"
|
||||
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
|
@ -4208,9 +4232,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.72"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "046ceba58ff062da072c7cb4ba5b22a37f00a302483f7e2a6cdc18fedbdc1fd3"
|
||||
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
|
@ -4235,9 +4259,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.72"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ef9aa01d36cda046f797c57959ff5f3c615c9cc63997a8d545831ec7976819b"
|
||||
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
|
||||
dependencies = [
|
||||
"quote 1.0.6",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -4245,9 +4269,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.72"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96eb45c1b2ee33545a813a92dbb53856418bf7eb54ab34f7f7ff1448a5b3735d"
|
||||
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.6",
|
||||
|
@ -4258,9 +4282,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.72"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7148f4696fb4960a346eaa60bbfb42a1ac4ebba21f750f75fc1375b098d5ffa"
|
||||
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
/target/
|
||||
/farf/
|
||||
/node_modules/
|
||||
/package-lock.json
|
||||
/target/
|
||||
|
|
|
@ -77,6 +77,10 @@ solana-program = { path = "program", version = "=1.10.0" }
|
|||
solana-sdk-macro = { path = "macro", version = "=1.10.0" }
|
||||
thiserror = "1.0"
|
||||
uriparse = "0.6.3"
|
||||
wasm-bindgen = "0.2"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
js-sys = "0.3.55"
|
||||
|
||||
[dev-dependencies]
|
||||
curve25519-dalek = "3.2.0"
|
||||
|
|
|
@ -373,3 +373,31 @@ 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()
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
program/package.json
|
|
@ -0,0 +1,2 @@
|
|||
/node_modules/
|
||||
/package-lock.json
|
|
@ -42,6 +42,13 @@ libsecp256k1 = "0.6.0"
|
|||
rand = "0.7.0"
|
||||
solana-logger = { path = "../../logger", version = "=1.10.0" }
|
||||
itertools = "0.10.1"
|
||||
wasm-bindgen = "0.2"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
console_error_panic_hook = "0.1.7"
|
||||
console_log = "0.2.0"
|
||||
js-sys = "0.3.55"
|
||||
getrandom = { version = "0.1", features = ["wasm-bindgen"] }
|
||||
|
||||
[target.'cfg(not(target_pointer_width = "64"))'.dependencies]
|
||||
parking_lot = "0.11"
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"devDependencies": {
|
||||
"chai": "^4.3.4",
|
||||
"mocha": "^9.1.2",
|
||||
"prettier": "^2.4.1"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "npm run build",
|
||||
"build": "wasm-pack build --target nodejs --dev --out-dir node_modules/crate --out-name crate",
|
||||
"pretty": "prettier --check 'tests/*.mjs'",
|
||||
"pretty:fix": "prettier --write 'tests/*.mjs'",
|
||||
"test": "mocha 'tests/*.mjs'"
|
||||
}
|
||||
}
|
|
@ -52,6 +52,12 @@ pub mod stake_history;
|
|||
pub mod system_instruction;
|
||||
pub mod system_program;
|
||||
pub mod sysvar;
|
||||
pub mod wasm;
|
||||
|
||||
#[cfg(target_arch = "bpf")]
|
||||
pub use solana_sdk_macro::wasm_bindgen_stub as wasm_bindgen;
|
||||
#[cfg(not(target_arch = "bpf"))]
|
||||
pub use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
pub mod config {
|
||||
pub mod program {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(clippy::integer_arithmetic)]
|
||||
use {
|
||||
crate::{decode_error::DecodeError, hash::hashv},
|
||||
crate::{decode_error::DecodeError, hash::hashv, wasm_bindgen},
|
||||
borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
|
||||
bytemuck::{Pod, Zeroable},
|
||||
num_derive::{FromPrimitive, ToPrimitive},
|
||||
|
@ -48,6 +48,7 @@ impl From<u64> for PubkeyError {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[repr(transparent)]
|
||||
#[derive(
|
||||
AbiExample,
|
||||
|
@ -67,7 +68,7 @@ impl From<u64> for PubkeyError {
|
|||
Serialize,
|
||||
Zeroable,
|
||||
)]
|
||||
pub struct Pubkey([u8; 32]);
|
||||
pub struct Pubkey(pub(crate) [u8; 32]);
|
||||
|
||||
impl crate::sanitize::Sanitize for Pubkey {}
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
//! solana-program Javascript interface
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub mod pubkey;
|
||||
|
||||
/// Initialize Javascript logging and panic handler
|
||||
#[wasm_bindgen]
|
||||
pub fn init() {
|
||||
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||
console_log::init_with_level(log::Level::Info).unwrap();
|
||||
}
|
||||
|
||||
pub fn display_to_jsvalue<T: std::fmt::Display>(display: T) -> JsValue {
|
||||
display.to_string().into()
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
//! `Pubkey` Javascript interface
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
#![allow(non_snake_case)]
|
||||
use {
|
||||
crate::{pubkey::*, wasm::display_to_jsvalue},
|
||||
js_sys::{Array, Uint8Array},
|
||||
wasm_bindgen::{prelude::*, JsCast},
|
||||
};
|
||||
|
||||
fn js_value_to_seeds_vec(array_of_uint8_arrays: &[JsValue]) -> Result<Vec<Vec<u8>>, JsValue> {
|
||||
let vec_vec_u8 = array_of_uint8_arrays
|
||||
.iter()
|
||||
.filter_map(|u8_array| {
|
||||
u8_array
|
||||
.dyn_ref::<Uint8Array>()
|
||||
.map(|u8_array| u8_array.to_vec())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if vec_vec_u8.len() != array_of_uint8_arrays.len() {
|
||||
Err("Invalid Array of Uint8Arrays".into())
|
||||
} else {
|
||||
Ok(vec_vec_u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Pubkey {
|
||||
/// Create a new Pubkey object
|
||||
///
|
||||
/// * `value` - optional public key as a base58 encoded string, `Uint8Array`, `[number]`
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn constructor(value: JsValue) -> Result<Pubkey, JsValue> {
|
||||
if let Some(base58_str) = value.as_string() {
|
||||
base58_str.parse::<Pubkey>().map_err(display_to_jsvalue)
|
||||
} else if let Some(uint8_array) = value.dyn_ref::<Uint8Array>() {
|
||||
Ok(Pubkey::new(&uint8_array.to_vec()))
|
||||
} else if let Some(array) = value.dyn_ref::<Array>() {
|
||||
let mut bytes = vec![];
|
||||
let iterator = js_sys::try_iter(&array.values())?.expect("array to be iterable");
|
||||
for x in iterator {
|
||||
let x = x?;
|
||||
|
||||
if let Some(n) = x.as_f64() {
|
||||
if n >= 0. && n <= 255. {
|
||||
bytes.push(n as u8);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return Err(format!("Invalid array argument: {:?}", x).into());
|
||||
}
|
||||
Ok(Pubkey::new(&bytes))
|
||||
} else if value.is_undefined() {
|
||||
Ok(Pubkey::default())
|
||||
} else {
|
||||
Err("Unsupported argument".into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the base58 string representation of the public key
|
||||
pub fn toString(&self) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
|
||||
/// Check if a `Pubkey` is on the ed25519 curve.
|
||||
pub fn isOnCurve(&self) -> bool {
|
||||
self.is_on_curve()
|
||||
}
|
||||
|
||||
/// Checks if two `Pubkey`s are equal
|
||||
pub fn equals(&self, other: &Pubkey) -> bool {
|
||||
self == other
|
||||
}
|
||||
|
||||
/// Return the `Uint8Array` representation of the public key
|
||||
pub fn toBytes(&self) -> Box<[u8]> {
|
||||
self.0.clone().into()
|
||||
}
|
||||
|
||||
/// Derive a Pubkey from another Pubkey, string seed, and a program id
|
||||
pub fn createWithSeed(base: &Pubkey, seed: &str, owner: &Pubkey) -> Result<Pubkey, JsValue> {
|
||||
Pubkey::create_with_seed(base, seed, owner).map_err(display_to_jsvalue)
|
||||
}
|
||||
|
||||
/// Derive a program address from seeds and a program id
|
||||
pub fn createProgramAddress(
|
||||
seeds: Box<[JsValue]>,
|
||||
program_id: &Pubkey,
|
||||
) -> Result<Pubkey, JsValue> {
|
||||
let seeds_vec = js_value_to_seeds_vec(&seeds)?;
|
||||
let seeds_slice = seeds_vec
|
||||
.iter()
|
||||
.map(|seed| seed.as_slice())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Pubkey::create_program_address(seeds_slice.as_slice(), program_id)
|
||||
.map_err(display_to_jsvalue)
|
||||
}
|
||||
|
||||
/// Find a valid program address
|
||||
///
|
||||
/// Returns:
|
||||
/// * `[PubKey, number]` - the program address and bump seed
|
||||
pub fn findProgramAddress(
|
||||
seeds: Box<[JsValue]>,
|
||||
program_id: &Pubkey,
|
||||
) -> Result<JsValue, JsValue> {
|
||||
let seeds_vec = js_value_to_seeds_vec(&seeds)?;
|
||||
let seeds_slice = seeds_vec
|
||||
.iter()
|
||||
.map(|seed| seed.as_slice())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let (address, bump_seed) = Pubkey::find_program_address(seeds_slice.as_slice(), program_id);
|
||||
|
||||
let result = Array::new_with_length(2);
|
||||
result.set(0, address.into());
|
||||
result.set(1, bump_seed.into());
|
||||
Ok(result.into())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
import { expect } from "chai";
|
||||
import { init, Pubkey } from "crate";
|
||||
init();
|
||||
|
||||
// TODO: wasm_bindgen doesn't currently support exporting constants
|
||||
const MAX_SEED_LEN = 32;
|
||||
|
||||
describe("Pubkey", function () {
|
||||
it("invalid", () => {
|
||||
expect(() => {
|
||||
new Pubkey([
|
||||
3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
]);
|
||||
}).to.throw();
|
||||
|
||||
expect(() => {
|
||||
new Pubkey([
|
||||
'invalid', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
]);
|
||||
}).to.throw();
|
||||
|
||||
expect(() => {
|
||||
new Pubkey(
|
||||
"0x300000000000000000000000000000000000000000000000000000000000000000000"
|
||||
);
|
||||
}).to.throw();
|
||||
|
||||
expect(() => {
|
||||
new Pubkey(
|
||||
"0x300000000000000000000000000000000000000000000000000000000000000"
|
||||
);
|
||||
}).to.throw();
|
||||
|
||||
expect(() => {
|
||||
new Pubkey(
|
||||
"135693854574979916511997248057056142015550763280047535983739356259273198796800000"
|
||||
);
|
||||
}).to.throw();
|
||||
|
||||
expect(() => {
|
||||
new Pubkey("12345");
|
||||
}).to.throw();
|
||||
});
|
||||
|
||||
it("toString", () => {
|
||||
const key = new Pubkey("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3");
|
||||
expect(key.toString()).to.eq("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3");
|
||||
|
||||
const key2 = new Pubkey("1111111111111111111111111111BukQL");
|
||||
expect(key2.toString()).to.eq("1111111111111111111111111111BukQL");
|
||||
|
||||
const key3 = new Pubkey("11111111111111111111111111111111");
|
||||
expect(key3.toString()).to.eq("11111111111111111111111111111111");
|
||||
|
||||
const key4 = new Pubkey([
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
]);
|
||||
expect(key4.toString()).to.eq("11111111111111111111111111111111");
|
||||
});
|
||||
|
||||
it("toBytes", () => {
|
||||
const key = new Pubkey("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3");
|
||||
expect(key.toBytes()).to.deep.equal(
|
||||
new Uint8Array([
|
||||
3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
])
|
||||
);
|
||||
|
||||
const key2 = new Pubkey();
|
||||
expect(key2.toBytes()).to.deep.equal(
|
||||
new Uint8Array([
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("isOnCurve", () => {
|
||||
let onCurve = new Pubkey("J4NYrSRccTUGXP7wmFwiByakqWKZb5RwpiAoskpgAQRb");
|
||||
expect(onCurve.isOnCurve()).to.be.true;
|
||||
|
||||
let offCurve = new Pubkey("12rqwuEgBYiGhBrDJStCiqEtzQpTTiZbh7teNVLuYcFA");
|
||||
expect(offCurve.isOnCurve()).to.be.false;
|
||||
});
|
||||
|
||||
it("equals", () => {
|
||||
const arrayKey = new Pubkey([
|
||||
3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
]);
|
||||
const base58Key = new Pubkey("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3");
|
||||
|
||||
expect(arrayKey.equals(base58Key)).to.be.true;
|
||||
});
|
||||
|
||||
it("createWithSeed", async () => {
|
||||
const defaultPublicKey = new Pubkey("11111111111111111111111111111111");
|
||||
const derivedKey = Pubkey.createWithSeed(
|
||||
defaultPublicKey,
|
||||
"limber chicken: 4/45",
|
||||
defaultPublicKey
|
||||
);
|
||||
|
||||
expect(
|
||||
derivedKey.equals(
|
||||
new Pubkey("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq")
|
||||
)
|
||||
).to.be.true;
|
||||
});
|
||||
|
||||
it("createProgramAddress", async () => {
|
||||
const programId = new Pubkey("BPFLoader1111111111111111111111111111111111");
|
||||
const publicKey = new Pubkey("SeedPubey1111111111111111111111111111111111");
|
||||
|
||||
let programAddress = Pubkey.createProgramAddress(
|
||||
[Buffer.from("", "utf8"), Buffer.from([1])],
|
||||
programId
|
||||
);
|
||||
expect(
|
||||
programAddress.equals(
|
||||
new Pubkey("3gF2KMe9KiC6FNVBmfg9i267aMPvK37FewCip4eGBFcT")
|
||||
)
|
||||
).to.be.true;
|
||||
|
||||
programAddress = Pubkey.createProgramAddress(
|
||||
[Buffer.from("☉", "utf8")],
|
||||
programId
|
||||
);
|
||||
expect(
|
||||
programAddress.equals(
|
||||
new Pubkey("7ytmC1nT1xY4RfxCV2ZgyA7UakC93do5ZdyhdF3EtPj7")
|
||||
)
|
||||
).to.be.true;
|
||||
|
||||
programAddress = Pubkey.createProgramAddress(
|
||||
[Buffer.from("Talking", "utf8"), Buffer.from("Squirrels", "utf8")],
|
||||
programId
|
||||
);
|
||||
expect(
|
||||
programAddress.equals(
|
||||
new Pubkey("HwRVBufQ4haG5XSgpspwKtNd3PC9GM9m1196uJW36vds")
|
||||
)
|
||||
).to.be.true;
|
||||
|
||||
programAddress = Pubkey.createProgramAddress(
|
||||
[publicKey.toBytes()],
|
||||
programId
|
||||
);
|
||||
expect(
|
||||
programAddress.equals(
|
||||
new Pubkey("GUs5qLUfsEHkcMB9T38vjr18ypEhRuNWiePW2LoK4E3K")
|
||||
)
|
||||
).to.be.true;
|
||||
|
||||
const programAddress2 = Pubkey.createProgramAddress(
|
||||
[Buffer.from("Talking", "utf8")],
|
||||
programId
|
||||
);
|
||||
expect(programAddress.equals(programAddress2)).to.eq(false);
|
||||
|
||||
expect(() => {
|
||||
Pubkey.createProgramAddress([Buffer.alloc(MAX_SEED_LEN + 1)], programId);
|
||||
}).to.throw();
|
||||
});
|
||||
|
||||
it("findProgramAddress", async () => {
|
||||
const programId = new Pubkey("BPFLoader1111111111111111111111111111111111");
|
||||
let [programAddress, nonce] = Pubkey.findProgramAddress(
|
||||
[Buffer.from("", "utf8")],
|
||||
programId
|
||||
);
|
||||
expect(
|
||||
programAddress.equals(
|
||||
Pubkey.createProgramAddress(
|
||||
[Buffer.from("", "utf8"), Buffer.from([nonce])],
|
||||
programId
|
||||
)
|
||||
)
|
||||
).to.be.true;
|
||||
});
|
||||
});
|
|
@ -47,6 +47,7 @@ pub mod system_transaction;
|
|||
pub mod timing;
|
||||
pub mod transaction;
|
||||
pub mod transport;
|
||||
pub mod wasm;
|
||||
|
||||
/// Same as `declare_id` except report that this id has been deprecated
|
||||
pub use solana_sdk_macro::declare_deprecated_id;
|
||||
|
|
|
@ -17,9 +17,11 @@ use {
|
|||
io::{Read, Write},
|
||||
path::Path,
|
||||
},
|
||||
wasm_bindgen::prelude::*,
|
||||
};
|
||||
|
||||
/// A vanilla Ed25519 key pair
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug)]
|
||||
pub struct Keypair(ed25519_dalek::Keypair);
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
//! `Keypair` Javascript interface
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
#![allow(non_snake_case)]
|
||||
use {
|
||||
crate::signer::{keypair::Keypair, Signer},
|
||||
solana_program::{pubkey::Pubkey, wasm::display_to_jsvalue},
|
||||
wasm_bindgen::prelude::*,
|
||||
};
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Keypair {
|
||||
/// Create a new `Keypair `
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn constructor() -> Keypair {
|
||||
Keypair::new()
|
||||
}
|
||||
|
||||
/// Convert a `Keypair` to a `Uint8Array`
|
||||
pub fn toBytes(&self) -> Box<[u8]> {
|
||||
self.to_bytes().into()
|
||||
}
|
||||
|
||||
/// Recover a `Keypair` from a `Uint8Array`
|
||||
pub fn fromBytes(bytes: &[u8]) -> Result<Keypair, JsValue> {
|
||||
Keypair::from_bytes(bytes).map_err(display_to_jsvalue)
|
||||
}
|
||||
|
||||
/// Return the `Pubkey` for this `Keypair`
|
||||
#[wasm_bindgen(js_name = pubkey)]
|
||||
pub fn js_pubkey(&self) -> Pubkey {
|
||||
// `wasm_bindgen` does not support traits (`Signer) yet
|
||||
self.pubkey()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
//! solana-sdk Javascript interface
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
|
||||
pub mod keypair;
|
|
@ -0,0 +1,14 @@
|
|||
import { expect } from "chai";
|
||||
import { init, Keypair } from "crate";
|
||||
init();
|
||||
|
||||
describe("Keypair", function () {
|
||||
it("works", () => {
|
||||
const keypair = new Keypair();
|
||||
let bytes = keypair.toBytes();
|
||||
expect(bytes).to.have.length(64);
|
||||
|
||||
const recoveredKeypair = Keypair.fromBytes(bytes);
|
||||
expect(keypair.pubkey().equals(recoveredKeypair.pubkey()));
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue