PageSourceSearch

https://noir-lang.org/docs/assets/js/b35636fe.01fbcbce.js

js noir-lang.org collected 2026-10-03 22:50:22 UTC 11,707 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdocs=globalThis.webpackChunkdocs||[]).push([[647],{96837(e,n,t){t.d(n,{Ay:()=>o});var i=t(74848),s=t(28453);function r(e){const n={a:"a",admonition:"admonition",p:"p",strong:"strong",...(0,s.R)(),...e.components};return(0,i.jsxs)(n.admonition,{title:"Experimental Feature",type:"caution",children:[(0,i.jsx)(n.p,{children:"This feature is experimental. The documentation may be incomplete or out of date, which means it could change in future versions, potentially causing unexpected behavior or not working as expected."}),(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Contributions Welcome:"})," If you notice any inaccuracies or potential improvements, please consider contributing. Visit our GitHub repository to make your contributions: ",(0,i.jsx)(n.a,{href:"https://github.com/noir-lang/noir",children:"Contribute Here"}),"."]})]})}function o(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(r,{...e})}):r(e)}t.d(n,["RM",0,[]])},37890(e,n,t){t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>d,default:()=>h,frontMatter:()=>c,metadata:()=>i,toc:()=>u});const i=JSON.parse('{"id":"guides/debugging/debugging_with_the_repl","title":"Using the REPL Debugger","description":"Step-by-step guide on how to debug your Noir circuits with the REPL Debugger.","source":"@site/versioned_docs/version-v1.0.0-rc.1/guides/debugging/debugging_with_the_repl.mdx","sourceDirName":"guides/
1debugging","slug":"/guides/debugging/debugging_with_the_repl","permalink":"/docs/v1.0.0-rc.1/guides/debugging/debugging_with_the_repl","draft":false,"unlisted":false,"editUrl":"https://github.com/noir-lang/noir/edit/master/docs/versioned_docs/version-v1.0.0-rc.1/guides/debugging/debugging_with_the_repl.mdx","tags":[],"version":"v1.0.0-rc.1","frontMatter":{"title":"Using the REPL Debugger","description":"Step-by-step guide on how to debug your Noir circuits with the REPL Debugger.","keywords":["Nargo","Noir CLI","Noir Debugger","REPL"]},"sidebar":"sidebar","previous":{"title":"Using the VS Code Debugger","permalink":"/docs/v1.0.0-rc.1/guides/debugging/debugging_with_vs_code"},"next":{"title":"Thinking in Circuits","permalink":"/docs/v1.0.0-rc.1/guides/thinking_in_circuits"}}');var s=t(74848),r=t(28453),o=t(96837);const c={title:"Using the REPL Debugger",description:"Step-by-step guide on how to debug your Noir circuits with the REPL Debugger.",keywords:["Nargo","Noir CLI","Noir Debugger","REPL"]},d=void 0,a={},u=[...o.RM,{value:"Pre-requisites",id:"pre-requisites",level:4},{value:"Debugging a simple circuit",id:"debugging-a-simple-circuit",level:2},{value:"Debugging a test function",id:"debugging-a-test-function",level:2},{value:"Test result",id:"test-result",level:3}];function l(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",h4:"h4",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(o.Ay,{}),"\n",(0,s.jsx)(n.h4,{id:"pre-requisites",children:"Pre-requisites"}),"\n",(0,s.jsx)(n.p,{children:"In order to use the REPL debugger, first you need to install recent enough versions of Nargo."}),"\n",(0,s.jsx)(n.h2,{id:"debugging-a-simple-circuit",children:"Debugging a simple circuit"}),"\n",(0,s.jsx)(n.p,{children:"Let's debug a simple circuit:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:"fn main(x : Field, y : pub Field) {\n    assert(x != y);\n}\n"})}),"\n",(0,s.jsx)(n.p,{children:"To start the REPL debugger, using a terminal, go to a Noir circuit's home directory. Then:"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"$ nargo debug"})}),"\n",(0,s.jsx)(n.p,{children:"You should be seeing this in your terminal:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"[main] Starting debugger\nAt ~/noir-examples/recursion/circuits/main/src/main.nr:1:9\n  1 -> fn main(x : Field, y : pub Field) {\n  2        assert(x != y);\n  3    }\n>\n"})}),"\n",(0,s.jsx)(n.p,{children:"The debugger displays the current Noir code location, and it is now waiting for us to drive it."}),"\n",(0,s.jsxs)(n.p,{children:["Let's first take a look at the available commands. For that we'll use the ",(0,s.jsx)(n.code,{children:"help"})," command."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"> help\nAvailable commands:\n\n  opcodes                          display ACIR opcodes\n  into                             step into to the next opcode\n  next                             step until a new source location is reached\n  out                              step until a new source location is reached\n                                   and the current stack frame is finished\n  break LOCATION:OpcodeLocation    add a breakpoint at an opcode location\n  over                             step until a new source location is reached\n                                   without diving into function calls\n  restart                          restart the debugging session\n  delete LOCATION:OpcodeLocation   delete breakpoint at an opcode location\n  witness                          show witness map\n  witness index:u32                display a single witness from the witness map\n  witness index:u32 value:String   update a witness with the given value\n  memset index:usize value:String  update a memory cell with the given\n                                   value\n  continue                         continue execution until the end of the\n                                   program\n  vars                             show variable values available at this point\
1n                                   in execution\n  stacktrace                       display the current stack trace\n  memory                           show memory (valid when executing unconstrained code)\n  step                             step to the next ACIR opcode\n\nOther commands:\n\n  help  Show this help message\n  quit  Quit repl\n\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Some commands operate only for unconstrained functions, such as ",(0,s.jsx)(n.code,{children:"memory"})," and ",(0,s.jsx)(n.code,{children:"memset"}),". If you try to use them while execution is paused at an ACIR opcode, the debugger will simply inform you that you are not executing unconstrained code:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"> memory\nUnconstrained VM memory not available\n>\n"})}),"\n",(0,s.jsx)(n.p,{children:"Before continuing, we can take a look at the initial witness map:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"> witness\n_0 = 1\n_1 = 2\n>\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Cool, since ",(0,s.jsx)(n.code,{children:"x==1"}),", ",(0,s.jsx)(n.code,{children:"y==2"}),", and we want to check that ",(0,s.jsx)(n.code,{children:"x != y"}),", our circuit should succeed. At this point we could intervene and use the witness setter command to change one of the witnesses. Let's set ",(0,s.jsx)(n.code,{children:"y=3"}),", then back to 2, so we don't affect the expected result:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"> witness\n_0 = 1\n_1 = 2\n> witness 1 3\n_1 = 3\n> witness\n_0 = 1\n_1 = 3\n> witness 1 2\n_1 = 2\n> witness\n_0 = 1\n_1 = 2\n>\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Now we can inspect the current state of local variables. For that we use the ",(0,s.jsx)(n.code,{children:"vars"})," command."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"> vars\n>\n"})}),"\n",(0,s.jsxs)(n.p,{children:["We currently have no vars in context, since we are at the entry point of the program. Let's use ",(0,s.jsx)(n.code,{children:"next"})," to execute until the next point in the program."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"> vars\n> next\nAt ~/noir-examples/recursion/circuits/main/src/main.nr:1:20\n  1 -> fn main(x : Field, y : pub Field) {\n  2        assert(x != y);\n  3    }\n> vars\nx:Field = 0x01\n"})}),"\n",(0,s.jsxs)(n.p,{children:["As a result of stepping, the variable ",(0,s.jsx)(n.code,{children:"x"}),", whose initial value comes from the witness map, is now in context and returned by ",(0,s.jsx)(n.code,{children:"vars"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"> next\n  1    fn main(x : Field, y : pub Field) {\n  2 ->     assert(x != y);\n  3    }\n> vars\ny:Field = 0x02\nx:Field = 0x01\n"})}),"\n",(0,s.jsx)(n.p,{children:"Stepping again we can finally see both variables and their values. And now we can see that the next assertion should succeed."}),"\n",(0,s.jsx)(n.p,{children:"Let's continue to the end:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"> continue\n(Continuing execution...)\nFinished execution\n> q\n[main] Circuit witness successfully solved\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Upon quitting the debugger after a solved circuit, the resulting circuit witness gets saved, equivalent to what would happen if we had run the same circuit with ",(0,s.jsx)(n.code,{children:"nargo execute"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["We just went through the basics of debugging using Noir REPL debugger. For a comprehensive reference, check out ",(0,s.jsx)(n.a,{href:"/docs/v1.0.0-rc.1/tooling/debugger/debugger_repl",children:"the reference page"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"debugging-a-test-function",children:"Debugging a test function"}),"\n",(0,s.jsx)(n.p,{children:"Let's debug a simple test:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:'#[test]\nfn test_simple_equal() {\n    let x = 2;\n    let y = 1 + 1;\n    assert(x == y, "should be equal");\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["To debug a test function using the REPL debugger, navigate to a Noir project directory inside a terminal, and run the ",(0,s.jsx)(n.code,{children:"nargo debug"})," command passing the ",(0,s.jsx)(n.code,{children:"--test-name your_test_name_here"})," argument."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"nargo debug --test-name test_simple_equal\n"})}),"\n",(0,s.jsx)(n.p,{children:"After that, the debugger has started and works the same as debugging a main function, you can use any of the above explained commands to control the execution of the test function."}),"\n",(0,s.jsx)(n.h3,{id:"test-result",children:"Test result"}),"\n",(0,s.jsxs)(n.p,{children:["The debugger does not end the session automatically. Once you finish debugging the execution of the test function you will notice that the debugger remains in the ",(0,s.jsx)(n.code,{children:"Execution finished"})," state. When you are done debugging the test function you can exit the debugger by using the ",(0,s.jsx)(n.code,{children:"quit"}
1)," command. Once you finish the debugging session you should see the test result."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-text",children:"$ nargo debug --test-name test_simple_equal\n[simple_noir_project] Starting debugger\nAt opcode 0:0 :: BRILLIG CALL func 0: inputs: [], outputs: []\n> continue\n(Continuing execution...)\nFinished execution\n> quit\n[simple_noir_project] Circuit witness successfully solved\n[simple_noir_project] Testing test_simple_equal... ok\n"})})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},28453(e,n,t){t.d(n,{R:()=>o,x:()=>c});var i=t(96540);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.