Skip to content

Commit 9b713f8

Browse files
authored
fix: allow abi encoding arrays of structs from JS (#3867)
# Description ## Problem\* Resolves <!-- Link to GitHub Issue --> ## Summary\* We currently do not allow arrays of structs when abi encoding from JS due to the `InputValue` type being too restrictive. This PR loosens this and adds a test to demonstrate how this is used. ## Additional Context ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
1 parent a40269a commit 9b713f8

4 files changed

Lines changed: 128 additions & 1 deletion

File tree

tooling/noirc_abi_wasm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use js_witness_map::JsWitnessMap;
2727
#[wasm_bindgen(typescript_custom_section)]
2828
const INPUT_MAP: &'static str = r#"
2929
export type Field = string | number | boolean;
30-
export type InputValue = Field | Field[] | InputMap;
30+
export type InputValue = Field | Field[] | InputMap | InputMap[];
3131
export type InputMap = { [key: string]: InputValue };
3232
"#;
3333

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { expect } from '@esm-bundle/chai';
2+
import initNoirAbi, { abiEncode, abiDecode, WitnessMap } from '@noir-lang/noirc_abi';
3+
import { MyNestedStruct, MyStruct } from '../shared/structs';
4+
import { DecodedInputs } from '../types';
5+
6+
beforeEach(async () => {
7+
await initNoirAbi();
8+
});
9+
10+
it('correctly handles struct inputs', async () => {
11+
const { abi, inputs } = await import('../shared/structs');
12+
13+
const initial_witness: WitnessMap = abiEncode(abi, inputs);
14+
const decoded_inputs: DecodedInputs = abiDecode(abi, initial_witness);
15+
16+
const struct_arg: MyStruct = inputs.struct_arg as MyStruct;
17+
const struct_array_arg: MyStruct[] = inputs.struct_array_arg as MyStruct[];
18+
const nested_struct_arg: MyNestedStruct = inputs.nested_struct_arg as MyNestedStruct;
19+
20+
expect(BigInt(decoded_inputs.inputs.struct_arg.foo)).to.be.equal(BigInt(struct_arg.foo));
21+
expect(BigInt(decoded_inputs.inputs.struct_array_arg[0].foo)).to.be.equal(BigInt(struct_array_arg[0].foo));
22+
expect(BigInt(decoded_inputs.inputs.struct_array_arg[1].foo)).to.be.equal(BigInt(struct_array_arg[1].foo));
23+
expect(BigInt(decoded_inputs.inputs.struct_array_arg[2].foo)).to.be.equal(BigInt(struct_array_arg[2].foo));
24+
expect(BigInt(decoded_inputs.inputs.nested_struct_arg.foo.foo)).to.be.equal(BigInt(nested_struct_arg.foo.foo));
25+
expect(decoded_inputs.return_value).to.be.null;
26+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { expect } from 'chai';
2+
import { abiEncode, abiDecode, WitnessMap } from '@noir-lang/noirc_abi';
3+
import { MyNestedStruct, MyStruct } from '../shared/structs';
4+
import { DecodedInputs } from '../types';
5+
6+
it('correctly handles struct inputs', async () => {
7+
const { abi, inputs } = await import('../shared/structs');
8+
9+
const initial_witness: WitnessMap = abiEncode(abi, inputs);
10+
const decoded_inputs: DecodedInputs = abiDecode(abi, initial_witness);
11+
12+
const struct_arg: MyStruct = inputs.struct_arg as MyStruct;
13+
const struct_array_arg: MyStruct[] = inputs.struct_array_arg as MyStruct[];
14+
const nested_struct_arg: MyNestedStruct = inputs.nested_struct_arg as MyNestedStruct;
15+
16+
expect(BigInt(decoded_inputs.inputs.struct_arg.foo)).to.be.equal(BigInt(struct_arg.foo));
17+
expect(BigInt(decoded_inputs.inputs.struct_array_arg[0].foo)).to.be.equal(BigInt(struct_array_arg[0].foo));
18+
expect(BigInt(decoded_inputs.inputs.struct_array_arg[1].foo)).to.be.equal(BigInt(struct_array_arg[1].foo));
19+
expect(BigInt(decoded_inputs.inputs.struct_array_arg[2].foo)).to.be.equal(BigInt(struct_array_arg[2].foo));
20+
expect(BigInt(decoded_inputs.inputs.nested_struct_arg.foo.foo)).to.be.equal(BigInt(nested_struct_arg.foo.foo));
21+
expect(decoded_inputs.return_value).to.be.null;
22+
});
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { Abi, Field, InputMap } from '@noir-lang/noirc_abi';
2+
3+
export type MyStruct = {
4+
foo: Field;
5+
};
6+
7+
export type MyNestedStruct = {
8+
foo: MyStruct;
9+
};
10+
11+
export const abi: Abi = {
12+
parameters: [
13+
{
14+
name: 'struct_arg',
15+
type: { kind: 'struct', path: 'MyStruct', fields: [{ name: 'foo', type: { kind: 'field' } }] },
16+
visibility: 'private',
17+
},
18+
{
19+
name: 'struct_array_arg',
20+
type: {
21+
kind: 'array',
22+
type: {
23+
kind: 'struct',
24+
path: 'MyStruct',
25+
fields: [{ name: 'foo', type: { kind: 'field' } }],
26+
},
27+
length: 3,
28+
},
29+
visibility: 'private',
30+
},
31+
{
32+
name: 'nested_struct_arg',
33+
type: {
34+
kind: 'struct',
35+
path: 'MyNestedStruct',
36+
fields: [
37+
{
38+
name: 'foo',
39+
type: {
40+
kind: 'struct',
41+
path: 'MyStruct',
42+
fields: [{ name: 'foo', type: { kind: 'field' } }],
43+
},
44+
},
45+
],
46+
},
47+
visibility: 'private',
48+
},
49+
],
50+
param_witnesses: {
51+
struct_arg: [{ start: 1, end: 2 }],
52+
struct_array_arg: [{ start: 2, end: 5 }],
53+
nested_struct_arg: [{ start: 5, end: 6 }],
54+
},
55+
return_type: null,
56+
return_witnesses: [],
57+
};
58+
59+
export const inputs: InputMap = {
60+
struct_arg: {
61+
foo: '1',
62+
},
63+
struct_array_arg: [
64+
{
65+
foo: '2',
66+
},
67+
{
68+
foo: '3',
69+
},
70+
{
71+
foo: '4',
72+
},
73+
],
74+
nested_struct_arg: {
75+
foo: {
76+
foo: '5',
77+
},
78+
},
79+
};

0 commit comments

Comments
 (0)