From e5e52a81b31d7735b680e97a9bef89a010a99763 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:51:12 +0000 Subject: [PATCH] feat: add foreign call support to `noir_codegen` functions (#3933) # Description ## Problem\* Resolves ## Summary\* This PR exposes custom foreign call handler functionality into the functions which are codegened by `noir_codegen`. ## 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. --- .../src/monomorphization/mod.rs | 2 +- tooling/noir_codegen/src/index.ts | 10 ++- .../noir_codegen/test/assert_lt/src/main.nr | 1 + .../test/assert_lt/target/assert_lt.json | 2 +- tooling/noir_codegen/test/index.test.ts | 84 ++++++++++++++++++- 5 files changed, 93 insertions(+), 6 deletions(-) diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index 5bdd41eafaa..bb0972987e4 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -974,7 +974,7 @@ impl<'interner> Monomorphizer<'interner> { } /// Adds a function argument that contains type metadata that is required to tell - /// `println` how to convert values passed to an foreign call back to a human-readable string. + /// `println` how to convert values passed to an foreign call back to a human-readable string. /// The values passed to an foreign call will be a simple list of field elements, /// thus requiring extra metadata to correctly decode this list of elements. /// diff --git a/tooling/noir_codegen/src/index.ts b/tooling/noir_codegen/src/index.ts index 7bef216097a..19829cd06ff 100644 --- a/tooling/noir_codegen/src/index.ts +++ b/tooling/noir_codegen/src/index.ts @@ -9,7 +9,9 @@ const codegenPrelude = `/* Autogenerated file, do not edit! */ /* eslint-disable */ -import { Noir, InputMap, CompiledCircuit } from "@noir-lang/noir_js" +import { Noir, InputMap, CompiledCircuit, ForeignCallHandler } from "@noir-lang/noir_js" + +export { ForeignCallHandler } from "@noir-lang/noir_js" `; const codegenFunction = ( @@ -22,10 +24,12 @@ const codegenFunction = ( return `export const ${name}_circuit: CompiledCircuit = ${JSON.stringify(compiled_program)}; -export async function ${name}(${args_with_types}): Promise<${function_signature.returnValue}> { +export async function ${name}(${args_with_types}, foreignCallHandler?: ForeignCallHandler): Promise<${ + function_signature.returnValue + }> { const program = new Noir(${name}_circuit); const args: InputMap = { ${args} }; - const { returnValue } = await program.execute(args); + const { returnValue } = await program.execute(args, foreignCallHandler); return returnValue as ${function_signature.returnValue}; } `; diff --git a/tooling/noir_codegen/test/assert_lt/src/main.nr b/tooling/noir_codegen/test/assert_lt/src/main.nr index 32d5ff84722..ed370bd87c0 100644 --- a/tooling/noir_codegen/test/assert_lt/src/main.nr +++ b/tooling/noir_codegen/test/assert_lt/src/main.nr @@ -20,6 +20,7 @@ fn main( assert(my_struct.foo.foo); assert(string == "12345"); + print(x); assert(x < y); (x + y, 3, my_struct.foo) } diff --git a/tooling/noir_codegen/test/assert_lt/target/assert_lt.json b/tooling/noir_codegen/test/assert_lt/target/assert_lt.json index b1865ca5f86..be1b134d642 100644 --- a/tooling/noir_codegen/test/assert_lt/target/assert_lt.json +++ b/tooling/noir_codegen/test/assert_lt/target/assert_lt.json @@ -1 +1 @@ -{"noir_version":"0.22.0+528d7c9fa244611cd54636493c730e6ce0734ece","hash":9387426530776910287,"abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"},{"name":"array","type":{"kind":"array","length":5,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"private"},{"name":"my_struct","type":{"kind":"struct","path":"NestedStruct","fields":[{"name":"foo","type":{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]}}},{"name":"baz","type":{"kind":"integer","sign":"unsigned","width":64}}]},"visibility":"private"},{"name":"string","type":{"kind":"string","length":5},"visibility":"private"}],"param_witnesses":{"array":[{"start":3,"end":8}],"my_struct":[{"start":8,"end":73}],"string":[{"start":73,"end":78}],"x":[{"start":1,"end":2}],"y":[{"start":2,"end":3}]},"return_type":{"abi_type":{"kind":"tuple","fields":[{"kind":"integer","sign":"unsigned","width":64},{"kind":"integer","sign":"unsigned","width":64},{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]}]},"visibility":"public"},"return_witnesses":[80,81,82,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]},"bytecode":"H4sIAAAAAAAA/82Y6W/TQBDFNy5HylGgXAEKmHKF2xvbic3VUM62OaDwCYkPSeMIJFAQiui/j59iw+YFIoFnJVaKnF+OyXhmN7vvvVNKfVCTUUofTnZtGuwQL6SPssF7iPcS7yPen3H+myqLj+EVG7ps/JYZ1/fqQZA0aon2dc+rxf0o9IKwX490pMMoHNQi30+iIGrE/bjhxTrwEz0MY3+YBS7L5ejldVikuhwgPkh8iPgw8RLxEeKjxMeIl4mPE58gPkl8ivi0xT5X0hgVC32uKPk+n6G6nCU+R7xCfJ74AvFFYpf4EvEq8WXiK8RXia8RX7fY52oao2qhz1Ul3+cbVJebxLeIbxPfIb5LfI/YI9bENWKfOCAOievEDYt9jtIYkYU+R0q+zzHV5T7xA+KHxI+IHxOvETeJnxCvEz8lfkb8nPgF8UviV2p6/9+g9zeJt4hbxG31ax7lw8Y5oCk0h2zmuSGQZzLEGFjNc1Msz52hzTy35PJMbObZkstzYDPPtlyeO9ANjpodjnDOJSW39p1/z0vzC7+5dbHYZl072bWrJlosnxf5Z6DX1tXsnCkZz/N9xZnzmdIf4iwar+XfXzLeL3rzM8Uwf1wqZicrpPSBpCOX488DSdeImY8F4XrYWlRFY70VrOe8+v1lnh7lqTuC99wV7GuB+s39g/uf1828PnvFxtQ68YoNLblOXiv5/x0zpq2+v5HL27eZ57Zg31tGjpif2LCxkcNIzc1TbLIwDGESwhiEGYhNFqYfjD6YezD0YOLBuINZB4MOphxMLphSMKJgPsFwgskEYwlmkqsmptGqmphDMIRgAsH4gdkD8wRmBwwOmBowMmBewLCASYEFhk0ZBgSKDqMB5gIMBZgIEOUQ0RDOEMsQyBDFEMJrWR0hcnG4gJiFgIVohVCFOIUghXCCKMGBH/Vqq+nDy3L2vEidML8x/7bV9OHlfXZdya698Tj58nXsjkdubzBwdz+NP7qj78m34efR7g+ltqXnYRcAAA=="} \ No newline at end of file +{"noir_version":"0.22.0+6f69b3f511c8b4c51404ad4c18131bdf6b7f6a94","hash":3763979860977920209,"abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"},{"name":"array","type":{"kind":"array","length":5,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"private"},{"name":"my_struct","type":{"kind":"struct","path":"NestedStruct","fields":[{"name":"foo","type":{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]}}},{"name":"baz","type":{"kind":"integer","sign":"unsigned","width":64}}]},"visibility":"private"},{"name":"string","type":{"kind":"string","length":5},"visibility":"private"}],"param_witnesses":{"array":[{"start":3,"end":8}],"my_struct":[{"start":8,"end":73}],"string":[{"start":73,"end":78}],"x":[{"start":1,"end":2}],"y":[{"start":2,"end":3}]},"return_type":{"abi_type":{"kind":"tuple","fields":[{"kind":"integer","sign":"unsigned","width":64},{"kind":"integer","sign":"unsigned","width":64},{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]}]},"visibility":"public"},"return_witnesses":[98,99,100,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]},"bytecode":"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"} \ No newline at end of file diff --git a/tooling/noir_codegen/test/index.test.ts b/tooling/noir_codegen/test/index.test.ts index 70f3d5bbf89..822993b2f1e 100644 --- a/tooling/noir_codegen/test/index.test.ts +++ b/tooling/noir_codegen/test/index.test.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { assert_lt, MyStruct, u64 } from './codegen/index.js'; +import { assert_lt, MyStruct, u64, ForeignCallHandler } from './codegen/index.js'; it('codegens a callable function', async () => { const my_struct = { foo: true, bar: ['12345', '12345', '12345'] }; @@ -20,3 +20,85 @@ it('codegens a callable function', async () => { expect(constant).to.be.eq('0x03'); expect(struct).to.be.deep.eq({ foo: true, bar: ['12345', '12345', '12345'] }); }); + +it('allows passing a custom foreign call handler', async () => { + let observedName = ''; + let observedInputs: string[][] = []; + const foreignCallHandler: ForeignCallHandler = async (name: string, inputs: string[][]) => { + // Throwing inside the oracle callback causes a timeout so we log the observed values + // and defer the check against expected values until after the execution is complete. + observedName = name; + observedInputs = inputs; + + return []; + }; + + const my_struct = { foo: true, bar: ['12345', '12345', '12345'] }; + + const [sum, constant, struct]: [u64, u64, MyStruct] = await assert_lt( + '2', + '3', + [0, 0, 0, 0, 0], + { + foo: my_struct, + bar: [my_struct, my_struct, my_struct], + baz: '64', + }, + '12345', + foreignCallHandler, + ); + + expect(observedName).to.be.eq('print'); + expect(observedInputs).to.be.deep.eq([ + // add newline? + ['0x0000000000000000000000000000000000000000000000000000000000000000'], + // x + ['0x0000000000000000000000000000000000000000000000000000000000000002'], + // Type metadata + [ + '0x000000000000000000000000000000000000000000000000000000000000007b', + '0x0000000000000000000000000000000000000000000000000000000000000022', + '0x000000000000000000000000000000000000000000000000000000000000006b', + '0x0000000000000000000000000000000000000000000000000000000000000069', + '0x000000000000000000000000000000000000000000000000000000000000006e', + '0x0000000000000000000000000000000000000000000000000000000000000064', + '0x0000000000000000000000000000000000000000000000000000000000000022', + '0x000000000000000000000000000000000000000000000000000000000000003a', + '0x0000000000000000000000000000000000000000000000000000000000000022', + '0x0000000000000000000000000000000000000000000000000000000000000075', + '0x000000000000000000000000000000000000000000000000000000000000006e', + '0x0000000000000000000000000000000000000000000000000000000000000073', + '0x0000000000000000000000000000000000000000000000000000000000000069', + '0x0000000000000000000000000000000000000000000000000000000000000067', + '0x000000000000000000000000000000000000000000000000000000000000006e', + '0x0000000000000000000000000000000000000000000000000000000000000065', + '0x0000000000000000000000000000000000000000000000000000000000000064', + '0x0000000000000000000000000000000000000000000000000000000000000069', + '0x000000000000000000000000000000000000000000000000000000000000006e', + '0x0000000000000000000000000000000000000000000000000000000000000074', + '0x0000000000000000000000000000000000000000000000000000000000000065', + '0x0000000000000000000000000000000000000000000000000000000000000067', + '0x0000000000000000000000000000000000000000000000000000000000000065', + '0x0000000000000000000000000000000000000000000000000000000000000072', + '0x0000000000000000000000000000000000000000000000000000000000000022', + '0x000000000000000000000000000000000000000000000000000000000000002c', + '0x0000000000000000000000000000000000000000000000000000000000000022', + '0x0000000000000000000000000000000000000000000000000000000000000077', + '0x0000000000000000000000000000000000000000000000000000000000000069', + '0x0000000000000000000000000000000000000000000000000000000000000064', + '0x0000000000000000000000000000000000000000000000000000000000000074', + '0x0000000000000000000000000000000000000000000000000000000000000068', + '0x0000000000000000000000000000000000000000000000000000000000000022', + '0x000000000000000000000000000000000000000000000000000000000000003a', + '0x0000000000000000000000000000000000000000000000000000000000000036', + '0x0000000000000000000000000000000000000000000000000000000000000034', + '0x000000000000000000000000000000000000000000000000000000000000007d', + ], + // format string? + ['0x0000000000000000000000000000000000000000000000000000000000000000'], + ]); + + expect(sum).to.be.eq('0x05'); + expect(constant).to.be.eq('0x03'); + expect(struct).to.be.deep.eq({ foo: true, bar: ['12345', '12345', '12345'] }); +});