diff --git a/wasm/src/jsval.rs b/wasm/src/jsval.rs index 1fed2fae..17019983 100644 --- a/wasm/src/jsval.rs +++ b/wasm/src/jsval.rs @@ -1,5 +1,5 @@ use js_sys::JSON::stringify; -use js_sys::{Array, BigInt, Object, Reflect}; +use js_sys::{Array, BigInt, Object, Reflect, Uint8Array}; use wasm_bindgen::JsCast; use num_bigint::ToBigInt; @@ -190,6 +190,11 @@ pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { .and_then(|o| Object::try_from(&o).cloned()) .and_then(|o| location(&o)) .unwrap_or_else(|| sstart.clone()); + if Uint8Array::instanceof(v) { + // Explicitly handle uint8array conversion. + let as_uint8array = Uint8Array::unchecked_from_js(v.clone()); + return Some(Rc::new(SExp::Atom(loc, as_uint8array.to_vec()))); + } get_property(o, "pair") .and_then(|p| { let pa = Array::from(&p); diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index fa693240..2188ce31 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -281,21 +281,21 @@ interface ITuple { interface IProgram { toString(): string; as_pair(): ITuple; - listp(): bool; - nullp(): bool; + listp(): boolean; + nullp(): boolean; as_int(): number; as_bigint(): bigint; - as_bin(): [Uint8Array]; + as_bin(): Uint8Array; first(): IProgram; rest(): IProgram; cons(p: IProgram): IProgram; - run(code: IProgram, env: IProgram): [number, IProgram]; + run(env: IProgram): [number, IProgram]; list_len(): number; - equal_to(other: IProgram): bool; + equal_to(other: IProgram): boolean; as_javascript(): any; curry(args: [IProgram]): IProgram; - sha256tree(): [Uint8Array]; - uncurry_error(): [IProgram]; + sha256tree(): Uint8Array; + uncurry_error(): [IProgram, Array]; uncurry(): [IProgram, Array|null]; } "#; diff --git a/wasm/tests/clvm-tools-interface/package.json b/wasm/tests/clvm-tools-interface/package.json index 3fc737a5..a63cc6cd 100644 --- a/wasm/tests/clvm-tools-interface/package.json +++ b/wasm/tests/clvm-tools-interface/package.json @@ -8,7 +8,7 @@ "start": "webpack serve --config webpack.config.demo.js", "build": "webpack && tsc", "build:demo": "webpack --config webpack.config.demo.js", - "test": "jest", + "test": "tsc -p tstestconfig.json --noEmit && jest", "coverage": "npm run test -- --coverage", "prepare": "npm run build", "trypublish": "npm publish || true" diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index b8420fa8..96863fd6 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -1,10 +1,11 @@ -import type { Program, IProgram, ITuple } from '../../../../../pkg/clvm_tools_wasm.d.ts'; +import type { IProgram, ITuple } from '../../../../../pkg/clvm_tools_wasm.js'; +import type { G1Element } from 'bls-signatures'; import * as fs from 'fs'; import { resolve } from 'path'; import * as assert from 'assert'; import * as bls_loader from 'bls-signatures'; -const {h, t, Program} = require('../../../../../pkg/clvm_tools_wasm'); +const {h, t, Program} = require('../../../../../pkg/clvm_tools_wasm.js'); it('Has BLS signatures support', async () => { const bls = await bls_loader.default(); @@ -18,6 +19,28 @@ it('Has the "h" function', async () => { assert.equal([0x21, 0x20, 0x30, 0x31].toString(), unhexed.toString()); }); +it('Converts uint8arrays', async () => { + let ua = new Uint8Array(3); + ua[0] = 0x30; + ua[1] = 0x81; + ua[2] = 0xff; + let p = Program.to(ua); + assert.equal([0x30, 0x81, 0xff].toString(), ua.toString()); +}); + +it('Converts uint8arrays from the "h" function', async () => { + let unhexed = h('8b5fd961cb1a826823c45a796b350d0d6ba2398829f249b1e535fd76f6d150b1'); + let p = Program.to([unhexed]); + assert.equal("ffa08b5fd961cb1a826823c45a796b350d0d6ba2398829f249b1e535fd76f6d150b180", p.toString()); +}); + +it('Converts a buffer', async () => { + let unhexed = h('8b5fd961cb1a826823c45a796b350d0d6ba2398829f249b1e535fd76f6d150b1'); + let b = Buffer.from(unhexed); + let p = Program.to([b]); + assert.equal("ffa08b5fd961cb1a826823c45a796b350d0d6ba2398829f249b1e535fd76f6d150b180", p.toString()); +}); + it('Converts to string', async () => { const converted_sexp = Program.to([1, 2, 3]); assert.equal("ff01ff02ff0380", converted_sexp.toString()); @@ -64,7 +87,7 @@ it('Has as_int', async () => { try { /*const non_int_value =*/ Program.to([7,13]).as_int(); assert.fail('was an int but should not be'); - } catch (e) { + } catch (e: any) { assert.equal(e.toString(), "not a number"); } }); @@ -75,7 +98,7 @@ it('Has as_bigint', async () => { try { /*const non_int_value =*/ Program.to([7,13]).as_bigint(); assert.fail(''); - } catch (e) { + } catch (e: any) { assert.equal(e.toString(), "not a number"); } }); @@ -87,13 +110,13 @@ it('Has first and rest', async () => { try { Program.to([]).first(); assert.fail("empty list had first"); - } catch (e) { + } catch (e: any) { assert.equal(e.toString(), "not a cons"); } try { Program.to([]).rest(); assert.fail("empty list had rest"); - } catch (e) { + } catch (e: any) { assert.equal(e.toString(), "not a cons"); } }); @@ -116,7 +139,7 @@ it('Has the t function', async () => { it('Has as_bin', async () => { const test_data = Program.to([7,8,9,10]); - const as_bin = test_data.as_bin(); + const as_bin: Uint8Array = test_data.as_bin(); assert.equal([255,7,255,8,255,9,255,10,128].toString(), as_bin.toString()); }); @@ -168,8 +191,8 @@ export class ChiaExample { constructor(MOD: IProgram) { this.MOD = MOD; } - public puzzle_for_synthetic_public_key(synthetic_public_key: G1Element): Program { - return this.MOD.curry(synthetic_public_key); + public puzzle_for_synthetic_public_key(synthetic_public_key: G1Element): IProgram { + return this.MOD.curry(Program.to(synthetic_public_key)); } } @@ -178,15 +201,16 @@ it('works as expected in context', async () => { const program_text = fs.readFileSync(resolve(__dirname, '../../../content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex'),'utf-8'); const MOD: IProgram = Program.from_hex(program_text); const ce = new ChiaExample(MOD); - const sk = bls.AugSchemeMPL.key_gen([ + const sk = bls.AugSchemeMPL.key_gen(new Uint8Array([ 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, 12, 62, 89, 110, 182, 9, 44, 20, 254, 22 - ]); + ])); const pk = bls.AugSchemeMPL.sk_to_g1(sk); // pk bytes 86243290bbcbfd9ae75bdece7981965350208eb5e99b04d5cd24e955ada961f8c0a162dee740be7bdc6c3c0613ba2eb1 // Expected puzzle hash = 30cdae3d54778db5eba21584c452cfb1a278136b2ec352ba44a52078efea7507 const target_puzzle = ce.puzzle_for_synthetic_public_key(pk); - assert.equal(target_puzzle.sha256tree().toString(), h('30cdae3d54778db5eba21584c452cfb1a278136b2ec352ba44a52078efea7507').toString()); + const shatree_result: Uint8Array = target_puzzle.sha256tree(); + assert.equal(shatree_result.toString(), h('30cdae3d54778db5eba21584c452cfb1a278136b2ec352ba44a52078efea7507').toString()); }); const cat2_puzzle = 'ff02ffff01ff02ff5effff04ff02ffff04ffff04ff05ffff04ffff0bff2cff0580ffff04ff0bff80808080ffff04ffff02ff17ff2f80ffff04ff5fffff04ffff02ff2effff04ff02ffff04ff17ff80808080ffff04ffff0bff82027fff82057fff820b7f80ffff04ff81bfffff04ff82017fffff04ff8202ffffff04ff8205ffffff04ff820bffff80808080808080808080808080ffff04ffff01ffffffff81ca3dff46ff0233ffff3c04ff01ff0181cbffffff02ff02ffff03ff05ffff01ff02ff32ffff04ff02ffff04ff0dffff04ffff0bff22ffff0bff2cff3480ffff0bff22ffff0bff22ffff0bff2cff5c80ff0980ffff0bff22ff0bffff0bff2cff8080808080ff8080808080ffff010b80ff0180ffff02ffff03ff0bffff01ff02ffff03ffff09ffff02ff2effff04ff02ffff04ff13ff80808080ff820b9f80ffff01ff02ff26ffff04ff02ffff04ffff02ff13ffff04ff5fffff04ff17ffff04ff2fffff04ff81bfffff04ff82017fffff04ff1bff8080808080808080ffff04ff82017fff8080808080ffff01ff088080ff0180ffff01ff02ffff03ff17ffff01ff02ffff03ffff20ff81bf80ffff0182017fffff01ff088080ff0180ffff01ff088080ff018080ff0180ffff04ffff04ff05ff2780ffff04ffff10ff0bff5780ff778080ff02ffff03ff05ffff01ff02ffff03ffff09ffff02ffff03ffff09ff11ff7880ffff0159ff8080ff0180ffff01818f80ffff01ff02ff7affff04ff02ffff04ff0dffff04ff0bffff04ffff04ff81b9ff82017980ff808080808080ffff01ff02ff5affff04ff02ffff04ffff02ffff03ffff09ff11ff7880ffff01ff04ff78ffff04ffff02ff36ffff04ff02ffff04ff13ffff04ff29ffff04ffff0bff2cff5b80ffff04ff2bff80808080808080ff398080ffff01ff02ffff03ffff09ff11ff2480ffff01ff04ff24ffff04ffff0bff20ff2980ff398080ffff010980ff018080ff0180ffff04ffff02ffff03ffff09ff11ff7880ffff0159ff8080ff0180ffff04ffff02ff7affff04ff02ffff04ff0dffff04ff0bffff04ff17ff808080808080ff80808080808080ff0180ffff01ff04ff80ffff04ff80ff17808080ff0180ffffff02ffff03ff05ffff01ff04ff09ffff02ff26ffff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ff0bff22ffff0bff2cff5880ffff0bff22ffff0bff22ffff0bff2cff5c80ff0580ffff0bff22ffff02ff32ffff04ff02ffff04ff07ffff04ffff0bff2cff2c80ff8080808080ffff0bff2cff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bff2cff058080ff0180ffff04ffff04ff28ffff04ff5fff808080ffff02ff7effff04ff02ffff04ffff04ffff04ff2fff0580ffff04ff5fff82017f8080ffff04ffff02ff7affff04ff02ffff04ff0bffff04ff05ffff01ff808080808080ffff04ff17ffff04ff81bfffff04ff82017fffff04ffff0bff8204ffffff02ff36ffff04ff02ffff04ff09ffff04ff820affffff04ffff0bff2cff2d80ffff04ff15ff80808080808080ff8216ff80ffff04ff8205ffffff04ff820bffff808080808080808080808080ff02ff2affff04ff02ffff04ff5fffff04ff3bffff04ffff02ffff03ff17ffff01ff09ff2dffff0bff27ffff02ff36ffff04ff02ffff04ff29ffff04ff57ffff04ffff0bff2cff81b980ffff04ff59ff80808080808080ff81b78080ff8080ff0180ffff04ff17ffff04ff05ffff04ff8202ffffff04ffff04ffff04ff24ffff04ffff0bff7cff2fff82017f80ff808080ffff04ffff04ff30ffff04ffff0bff81bfffff0bff7cff15ffff10ff82017fffff11ff8202dfff2b80ff8202ff808080ff808080ff138080ff80808080808080808080ff018080'; @@ -195,8 +219,8 @@ const cat2_curried_program = 'ff02ffff01ff02ffff01ff02ffff03ff0bffff01ff02ffff03 it('can uncurry an example program', async () => { const to_uncurry_text = fs.readFileSync(resolve(__dirname, '../../../content/test_cat2_program.hex'),'utf-8'); - const program: IProgram = Program.from_hex(to_uncurry_text); - const uncurried: Array = program.uncurry_error(); + const program = Program.from_hex(to_uncurry_text); + const uncurried = program.uncurry_error(); assert.equal(uncurried.length, 2); assert.equal(uncurried[1].length, 3); assert.equal(uncurried[0].toString(), cat2_puzzle); diff --git a/wasm/tests/clvm-tools-interface/tsconfig.json b/wasm/tests/clvm-tools-interface/tsconfig.json index 9ea99e98..655a5b6d 100644 --- a/wasm/tests/clvm-tools-interface/tsconfig.json +++ b/wasm/tests/clvm-tools-interface/tsconfig.json @@ -12,6 +12,7 @@ "suppressImplicitAnyIndexErrors": true, "lib": ["es2018", "dom"], "moduleResolution": "node", + "target": "es2020" }, "include": ["src/lib"], "exclude": ["src/lib/**/tests"], diff --git a/wasm/tests/clvm-tools-interface/tstestconfig.json b/wasm/tests/clvm-tools-interface/tstestconfig.json new file mode 100644 index 00000000..b47c040d --- /dev/null +++ b/wasm/tests/clvm-tools-interface/tstestconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "emitDeclarationOnly": false, + "noEmitOnError": true, + "strict": true, + }, + "include": ["src/lib/**/tests"], + "exclude": [] +}