{
  "base_url": "https://talk.nervos.org",
  "generated_at": "2026-05-02T17:42:11.444835+00:00",
  "since": "2026-05-01T17:42:03.155930+00:00",
  "until": "2026-05-02T17:42:03.155930+00:00",
  "window_hours": 24,
  "topics": [
    {
      "topic_id": 10224,
      "title": "CellScript 0.13 Preview: The Action Model and Syntax",
      "slug": "cellscript-0-13-preview-the-action-model-and-syntax",
      "url": "https://talk.nervos.org/t/cellscript-0-13-preview-the-action-model-and-syntax/10224",
      "created_at": "2026-05-01T15:34:27.229000+00:00",
      "last_posted_at": "2026-05-02T15:44:55.946000+00:00",
      "category_id": 49,
      "tags": [
        "CKB-VM",
        "CellScript"
      ],
      "posters": [
        "Original Poster, Most Recent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24116,
          "post_number": 2,
          "topic_id": 10224,
          "topic_title": "CellScript 0.13 Preview: The Action Model and Syntax",
          "topic_slug": "cellscript-0-13-preview-the-action-model-and-syntax",
          "author": "ArthurZhang",
          "created_at": "2026-05-02T15:44:55.946000+00:00",
          "updated_at": "2026-05-02T15:46:52.903000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/cellscript-0-13-preview-the-action-model-and-syntax/10224/2",
          "content_text": "0.13.1 Patch Plan Preview\nLocal Ergonomics and Syntax Governance\n1. Background\nCellScript 0.13.0 set to be released next week will establish the new action model:\nA transaction proposes a Cell transformation.\nAn action verifies whether that transformation is allowed.\nIn this model, an action is not a method call, not an account-storage mutation, and not a runtime constructor. It is a typed verifier case: it names the input evidence, names the proposed output evidence, and proves the relationship between them. The 0.13 tutorial already frames this explicitly: signature direction describes transaction topology, where scopes proof obligations, move declares a state edge, require states verifier constraints, and create constrains proposed outputs.\n0.13.1 does not change this model.\nInstead, 0.13.1 introduces two local syntax improvements:\npreserve sugar\naggregated require block\nBoth are intentionally small, local, and mechanically expandable into existing 0.13 core syntax.\nThe goal is to reduce repetitive notation without hiding verifier obligations.\n2. Design Principle\n0.13.1 follows one rule:\nReduce ceremony, not safety visibility.\nA syntax addition is acceptable only if:\nits desugared form is obvious;\nall security-relevant fields or expressions remain visible at the action site;\nit does not introduce remote policy lookup;\nit does not behave like replace;\naudit tooling can expand it back into canonical 0.13 require statements.\nThis keeps 0.13.1 aligned with the 0.13 philosophy:\nThe action header says what changes.\nThe where block proves why it is allowed.\n3. Feature 1: preserve Sugar\n3.1 Motivation\nA common 0.13 pattern is explicit field preservation:\nrequire output.seller == input.seller\nrequire output.price == input.price\nrequire output.payment_symbol == input.payment_symbol\nThis is clear, but repetitive.\n0.13.1 introduces local field-preservation sugar:\npreserve output from input {\nseller\nprice\npayment_symbol\n}\nThis desugars exactly to:\nrequire output.seller == input.seller\nrequire output.price == input.price\nrequire output.payment_symbol == input.payment_symbol\n3.2 Canonical Example\n0.13.0:\naction fill(input: Offer, payment: Token, buyer: Address)\n-> (output: Offer, seller_payment: Token)\nmove input.state: Live -> output.state: Filled\nwhere\nrequire output.seller == input.seller\nrequire output.price == input.price\nrequire output.payment_symbol == input.payment_symbol\nrequire payment.amount == input.price\nrequire payment.symbol == input.payment_symbol\nrequire output.buyer == buyer\nconsume payment\ncreate seller_payment = Token {\namount: payment.amount,\nsymbol: payment.symbol\n} with_lock(input.seller)\n0.13.1:\naction fill(input: Offer, payment: Token, buyer: Address)\n-> (output: Offer, seller_payment: Token)\nmove input.state: Live -> output.state: Filled\nwhere\npreserve output from input {\nseller\nprice\npayment_symbol\n}\nrequire {\npayment.amount == input.price\npayment.symbol == input.payment_symbol\noutput.buyer == buyer\n}\nconsume payment\ncreate seller_payment = Token {\namount: payment.amount,\nsymbol: payment.symbol\n} with_lock(input.seller)\nThe second version is shorter, but still audit-visible.\nThe auditor still sees exactly which fields are preserved:\nseller\nprice\npayment_symbol\nNothing is hidden behind a reusable policy or opaque replacement primitive.\n3.3 Rules\npreserve is a local field-preservation shorthand.\nAllowed:\npreserve output from input {\nseller\nprice\npayment_symbol\n}\nNot allowed:\npreserve output from input\nNot allowed:\npreserve output from input {\n*\n}\nNot allowed:\npreserve output from input except {\nstate\n}\nReason\nCellScript should use whitelist preservation, not blacklist preservation.\nWhitelist preservation is safe because every preserved field is visible at the action site.\nBlacklist preservation is dangerous because newly added fields may be accidentally preserved or accidentally left unaudited.\n3.4 Scope\nIn 0.13.1, preserve applies only to resource data fields.\nIt does not preserve Cell metadata such as:\nlock\ntype\ncapacity\nThose remain explicit for now:\nrequire output.lock_hash == input.lock_hash\nrequire output.type_hash == input.type_hash\nrequire output.capacity == input.capacity\nFuture versions may consider standard-library helpers such as:\nstd::cell::same_lock(output, input)\nstd::cell::same_type(output, input)\nor later namespaced sugar, but these should not be part of 0.13.1 core.\n4. Feature 2: Anonymous require Block\n4.1 Motivation\nLong runs of require statements are common:\nrequire payment.amount == input.price\nrequire payment.symbol == input.payment_symbol\nrequire output.buyer == buyer\n0.13.1 allows grouping them:\nrequire {\npayment.amount == input.price\npayment.symbol == input.payment_symbol\noutput.buyer == buyer\n}\nThis desugars into independent atomic require statements:\nrequire payment.amount == input.price\nrequire payment.symbol == input.payment_symbol\nrequire output.buyer == buyer\n4.2 Rules\nA require block may contain only pure boolean expressions.\nAllowed:\nrequire {\npayment.amount == input.price\npayment.symbol == input.payment_symbol\n}\nNot allowed:\nrequire {\nlet x = payment.amount\nx == input.price\n}\nNot allowed:\nrequire {\nconsume payment\n}\nNot allowed:\nrequire {\nif payment.amount == input.price {\noutput.buyer == buyer\n}\n}\nReason\nA require block is not a nested proof language.\nIt is only grouping sugar.\n4.3 No Named Blocks in 0.13.1\n0.13.1 should not introduce named require blocks.\nDo not add:\nrequire payment_valid {\npayment.amount == input.price\npayment.symbol == input.payment_symbol\n}\nReason:\nnames can mislead;\nnames may imply semantic status;\nnames invite future reusable policy calls;\nreusable proof labels risk becoming user-defined replace.\nFor 0.13.1, keep it anonymous:\nrequire {\npayment.amount == input.price\npayment.symbol == input.payment_symbol\n}\nIf future tooling needs diagnostics labels, consider an annotation form later:\nrequire @payment_valid {\npayment.amount == input.price\npayment.symbol == input.payment_symbol\n}\nBut that should remain metadata, not semantics.\n5. Syntax Governance\n0.13.1 should also introduce a formal syntax-governance note.\nThe goal is to define which features belong in core syntax, which belong in local sugar, which belong in standard library, and which should be avoided.\n5.1 Layer 1: Core Verifier Syntax\nCore syntax is small, stable, and directly tied to the Cell verifier model.\nExamples:\naction input -> output\nwhere\nmove input.state: A -> output.state: B\nflow\nrequire expr\ncreate output = T { ... }\nconsume\ndestroy\nread / protected / witness / lock_args\nThese are the verifier calculus.\nThey should remain minimal and explicit.\n5.2 Layer 2: Local Explicit Sugar\nLocal sugar may enter the language if it keeps all safety facts visible.\n0.13.1 local sugar:\npreserve output from input {\nfield\nfield\n}\nand:\nrequire {\nexpr\nexpr\n}\nThese are acceptable because they remain local and expandable.\n5.3 Layer 3: Standard-Library Advanced Patterns\nMore advanced protocol concepts should not enter core syntax immediately.\nExamples:\nconserve\npreserve_lock\npreserve_type\npreserve_capacity\nclaim helpers\nsettle helpers\ntransfer helpers\ncapacity accounting helpers\nreceipt redemption helpers\nThese should first live in standard-library categories such as:\nstd::cell\nstd::accounting\nstd::receipt\nstd::lifecycle\nstd::ckb\nThis makes the user mental model clear:\ncore syntax = verifier calculus\nstdlib helper = typed sugar / audit pattern\nFor example:\nrequire std::cell::same_lock(output, input)\nrequire std::cell::same_type(output, input)\nrequire std::accounting::conserved(input.amount, [left.amount, right.amount])\nEvery advanced standard-library primitive should have a canonical expansion into core CellScript.\n5.4 Layer 4: Non-Core / Avoided Features\nThe following should remain outside 0.13.1:\ngeneral policy primitive\nnamed reusable require blocks\nreplace / replaces\npreserve all\npreserve except\nimplicit transfer magic\ngeneral settle magic\ncapacity conservation sugar\ncross-module proof policy imports\nReason:\nThese features can hide proof obligations, lengthen audit paths, or recreate the ambiguity that replace was removed to avoid.\n6. Desugaring Requirements\n0.13.1 should define canonical expansion rules.\n6.1 preserve\nSource:\npreserve output from input {\nseller\nprice\npayment_symbol\n}\nCanonical expansion:\nrequire output.seller == input.seller\nrequire output.price == input.price\nrequire output.payment_symbol == input.payment_symbol\n6.2 require Block\nSource:\nrequire {\npayment.amount == input.price\npayment.symbol == input.payment_symbol\n}\nCanonical expansion:\nrequire payment.amount == input.price\nrequire payment.symbol == input.payment_symbol\n7. Example: Updated 0.13.1 Style\nenum OfferState {\nCreated,\nLive,\nFilled,\nCancelled,\n}\nresource Offer has store {\nstate: OfferState\nseller: Address\nbuyer: Address\nprice: u64\npayment_symbol: [u8; 8]\n}\nresource Token has store, destroy {\namount: u64\nsymbol: [u8; 8]\n}\nflow Offer.state {\nCreated -> Live;\nLive -> Filled;\nLive -> Cancelled;\n}\naction fill(input: Offer, payment: Token, buyer: Address)\n-> (output: Offer, seller_payment: Token)\nmove input.state: Live -> output.state: Filled\nwhere\npreserve output from input {\nseller\nprice\npayment_symbol\n}\nrequire {\npayment.amount == input.price\npayment.symbol == input.payment_symbol\noutput.buyer == buyer\n}\nconsume payment\ncreate seller_payment = Token {\namount: payment.amount,\nsymbol: payment.symbol\n} with_lock(input.seller)\nThis keeps the 0.13 action model intact while improving readability.\nThe action still clearly shows:\ninput evidence\noutput proposal\nstate edge\nfield continuity\npayment validation\ninput fate\noutput construction\n9. Final Summary\nThat is the current plan for the 0.13.1 patch.\nThe intention is deliberately modest: keep the 0.13 action model explicit, add only local ergonomics where the desugared form is obvious, and keep higher-level protocol patterns out of core syntax until they have proved themselves in real examples.\nAs always, comments are very welcome, especially on the boundary between useful local sugar and abstractions that might make audits harder.\nI would be particularly interested in feedback on:\nwhether preserve output from input { ... } feels clear enough as field-preservation sugar;\nwhether anonymous require { ... } blocks improve readability without implying a new proof abstraction;\nwhether advanced primitives such as conserve, preserve_lock, claim, settle, or transfer are better kept in standard-library categories rather than core syntax.",
          "content_html": "<h1><a name=\"p-24116-h-0131-patch-plan-preview-1\" class=\"anchor\" href=\"#p-24116-h-0131-patch-plan-preview-1\" aria-label=\"Heading link\"></a>0.13.1 Patch Plan Preview</h1>\n<h2><a name=\"p-24116-local-ergonomics-and-syntax-governance-2\" class=\"anchor\" href=\"#p-24116-local-ergonomics-and-syntax-governance-2\" aria-label=\"Heading link\"></a>Local Ergonomics and Syntax Governance</h2>\n<h2><a name=\"p-24116-h-1-background-3\" class=\"anchor\" href=\"#p-24116-h-1-background-3\" aria-label=\"Heading link\"></a>1. Background</h2>\n<p>CellScript 0.13.0 set to be released next week will establish the new action model:</p>\n<pre><code class=\"lang-plaintext\">A transaction proposes a Cell transformation.\nAn action verifies whether that transformation is allowed.\n</code></pre>\n<p>In this model, an <code>action</code> is not a method call, not an account-storage mutation, and not a runtime constructor. It is a typed verifier case: it names the input evidence, names the proposed output evidence, and proves the relationship between them. The 0.13 tutorial already frames this explicitly: signature direction describes transaction topology, <code>where</code> scopes proof obligations, <code>move</code> declares a state edge, <code>require</code> states verifier constraints, and <code>create</code> constrains proposed outputs.</p>\n<p>0.13.1 does <strong>not</strong> change this model.</p>\n<p>Instead, 0.13.1 introduces two local syntax improvements:</p>\n<ol>\n<li><code>preserve</code> sugar</li>\n<li>aggregated <code>require</code> block</li>\n</ol>\n<p>Both are intentionally small, local, and mechanically expandable into existing 0.13 core syntax.</p>\n<p>The goal is to reduce repetitive notation without hiding verifier obligations.</p>\n<hr>\n<h2><a name=\"p-24116-h-2-design-principle-4\" class=\"anchor\" href=\"#p-24116-h-2-design-principle-4\" aria-label=\"Heading link\"></a>2. Design Principle</h2>\n<p>0.13.1 follows one rule:</p>\n<blockquote>\n<p><strong>Reduce ceremony, not safety visibility.</strong></p>\n</blockquote>\n<p>A syntax addition is acceptable only if:</p>\n<ol>\n<li>its desugared form is obvious;</li>\n<li>all security-relevant fields or expressions remain visible at the action site;</li>\n<li>it does not introduce remote policy lookup;</li>\n<li>it does not behave like <code>replace</code>;</li>\n<li>audit tooling can expand it back into canonical 0.13 <code>require</code> statements.</li>\n</ol>\n<p>This keeps 0.13.1 aligned with the 0.13 philosophy:</p>\n<pre><code class=\"lang-plaintext\">The action header says what changes.\nThe where block proves why it is allowed.\n</code></pre>\n<hr>\n<h1><a name=\"p-24116-h-3-feature-1-preserve-sugar-5\" class=\"anchor\" href=\"#p-24116-h-3-feature-1-preserve-sugar-5\" aria-label=\"Heading link\"></a>3. Feature 1: <code>preserve</code> Sugar</h1>\n<h2><a name=\"p-24116-h-31-motivation-6\" class=\"anchor\" href=\"#p-24116-h-31-motivation-6\" aria-label=\"Heading link\"></a>3.1 Motivation</h2>\n<p>A common 0.13 pattern is explicit field preservation:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require output.seller == input.seller\nrequire output.price == input.price\nrequire output.payment_symbol == input.payment_symbol\n</code></pre>\n<p>This is clear, but repetitive.</p>\n<p>0.13.1 introduces local field-preservation sugar:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">preserve output from input {\n    seller\n    price\n    payment_symbol\n}\n</code></pre>\n<p>This desugars exactly to:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require output.seller == input.seller\nrequire output.price == input.price\nrequire output.payment_symbol == input.payment_symbol\n</code></pre>\n<hr>\n<h2><a name=\"p-24116-h-32-canonical-example-7\" class=\"anchor\" href=\"#p-24116-h-32-canonical-example-7\" aria-label=\"Heading link\"></a>3.2 Canonical Example</h2>\n<p><strong>0.13.0</strong>:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">action fill(input: Offer, payment: Token, buyer: Address)\n    -&gt; (output: Offer, seller_payment: Token)\n    move input.state: Live -&gt; output.state: Filled\nwhere\n    require output.seller == input.seller\n    require output.price == input.price\n    require output.payment_symbol == input.payment_symbol\n\n    require payment.amount == input.price\n    require payment.symbol == input.payment_symbol\n    require output.buyer == buyer\n\n    consume payment\n\n    create seller_payment = Token {\n        amount: payment.amount,\n        symbol: payment.symbol\n    } with_lock(input.seller)\n</code></pre>\n<p><strong>0.13.1:</strong></p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">action fill(input: Offer, payment: Token, buyer: Address)\n    -&gt; (output: Offer, seller_payment: Token)\n    move input.state: Live -&gt; output.state: Filled\nwhere\n    preserve output from input {\n        seller\n        price\n        payment_symbol\n    }\n\n    require {\n        payment.amount == input.price\n        payment.symbol == input.payment_symbol\n        output.buyer == buyer\n    }\n\n    consume payment\n\n    create seller_payment = Token {\n        amount: payment.amount,\n        symbol: payment.symbol\n    } with_lock(input.seller)\n</code></pre>\n<p>The second version is shorter, but still audit-visible.</p>\n<p>The auditor still sees exactly which fields are preserved:</p>\n<pre><code class=\"lang-plaintext\">seller\nprice\npayment_symbol\n</code></pre>\n<p>Nothing is hidden behind a reusable policy or opaque replacement primitive.</p>\n<hr>\n<h2><a name=\"p-24116-h-33-rules-8\" class=\"anchor\" href=\"#p-24116-h-33-rules-8\" aria-label=\"Heading link\"></a>3.3 Rules</h2>\n<p><code>preserve</code> is a <strong>local field-preservation shorthand</strong>.</p>\n<p>Allowed:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">preserve output from input {\n    seller\n    price\n    payment_symbol\n}\n</code></pre>\n<p>Not allowed:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">preserve output from input\n</code></pre>\n<p>Not allowed:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">preserve output from input {\n    *\n}\n</code></pre>\n<p>Not allowed:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">preserve output from input except {\n    state\n}\n</code></pre>\n<h3><a name=\"p-24116-reason-9\" class=\"anchor\" href=\"#p-24116-reason-9\" aria-label=\"Heading link\"></a>Reason</h3>\n<p>CellScript should use whitelist preservation, not blacklist preservation.</p>\n<p>Whitelist preservation is safe because every preserved field is visible at the action site.</p>\n<p>Blacklist preservation is dangerous because newly added fields may be accidentally preserved or accidentally left unaudited.</p>\n<hr>\n<h2><a name=\"p-24116-h-34-scope-10\" class=\"anchor\" href=\"#p-24116-h-34-scope-10\" aria-label=\"Heading link\"></a>3.4 Scope</h2>\n<p>In 0.13.1, <code>preserve</code> applies only to resource data fields.</p>\n<p><strong>It does not preserve Cell metadata such as:</strong></p>\n<pre><code class=\"lang-plaintext\">lock\ntype\ncapacity\n</code></pre>\n<p>Those remain explicit for now:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require output.lock_hash == input.lock_hash\nrequire output.type_hash == input.type_hash\nrequire output.capacity == input.capacity\n</code></pre>\n<p>Future versions may consider standard-library helpers such as:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">std::cell::same_lock(output, input)\nstd::cell::same_type(output, input)\n</code></pre>\n<p>or later namespaced sugar, but these should not be part of 0.13.1 core.</p>\n<hr>\n<h1><a name=\"p-24116-h-4-feature-2-anonymous-require-block-11\" class=\"anchor\" href=\"#p-24116-h-4-feature-2-anonymous-require-block-11\" aria-label=\"Heading link\"></a>4. Feature 2: Anonymous <code>require</code> Block</h1>\n<h2><a name=\"p-24116-h-41-motivation-12\" class=\"anchor\" href=\"#p-24116-h-41-motivation-12\" aria-label=\"Heading link\"></a>4.1 Motivation</h2>\n<p>Long runs of <code>require</code> statements are common:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require payment.amount == input.price\nrequire payment.symbol == input.payment_symbol\nrequire output.buyer == buyer\n</code></pre>\n<p>0.13.1 allows grouping them:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require {\n    payment.amount == input.price\n    payment.symbol == input.payment_symbol\n    output.buyer == buyer\n}\n</code></pre>\n<p>This desugars into independent atomic <code>require</code> statements:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require payment.amount == input.price\nrequire payment.symbol == input.payment_symbol\nrequire output.buyer == buyer\n</code></pre>\n<hr>\n<h2><a name=\"p-24116-h-42-rules-13\" class=\"anchor\" href=\"#p-24116-h-42-rules-13\" aria-label=\"Heading link\"></a>4.2 Rules</h2>\n<p>A <code>require</code> block may contain only pure boolean expressions.</p>\n<p>Allowed:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require {\n    payment.amount == input.price\n    payment.symbol == input.payment_symbol\n}\n</code></pre>\n<p>Not allowed:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require {\n    let x = payment.amount\n    x == input.price\n}\n</code></pre>\n<p>Not allowed:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require {\n    consume payment\n}\n</code></pre>\n<p>Not allowed:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require {\n    if payment.amount == input.price {\n        output.buyer == buyer\n    }\n}\n</code></pre>\n<h3><a name=\"p-24116-reason-14\" class=\"anchor\" href=\"#p-24116-reason-14\" aria-label=\"Heading link\"></a>Reason</h3>\n<p>A <code>require</code> block is not a nested proof language.</p>\n<p>It is only grouping sugar.</p>\n<hr>\n<h2><a name=\"p-24116-h-43-no-named-blocks-in-0131-15\" class=\"anchor\" href=\"#p-24116-h-43-no-named-blocks-in-0131-15\" aria-label=\"Heading link\"></a>4.3 No Named Blocks in 0.13.1</h2>\n<p>0.13.1 should not introduce named <code>require</code> blocks.</p>\n<p>Do not add:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require payment_valid {\n    payment.amount == input.price\n    payment.symbol == input.payment_symbol\n}\n</code></pre>\n<p>Reason:</p>\n<ol>\n<li>names can mislead;</li>\n<li>names may imply semantic status;</li>\n<li>names invite future reusable policy calls;</li>\n<li>reusable proof labels risk becoming user-defined <code>replace</code>.</li>\n</ol>\n<p>For 0.13.1, keep it anonymous:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require {\n    payment.amount == input.price\n    payment.symbol == input.payment_symbol\n}\n</code></pre>\n<p>If future tooling needs diagnostics labels, consider an annotation form later:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require @payment_valid {\n    payment.amount == input.price\n    payment.symbol == input.payment_symbol\n}\n</code></pre>\n<p>But that should remain metadata, not semantics.</p>\n<hr>\n<h1><a name=\"p-24116-h-5-syntax-governance-16\" class=\"anchor\" href=\"#p-24116-h-5-syntax-governance-16\" aria-label=\"Heading link\"></a>5. Syntax Governance</h1>\n<p>0.13.1 should also introduce a formal syntax-governance note.</p>\n<p>The goal is to define which features belong in core syntax, which belong in local sugar, which belong in standard library, and which should be avoided.</p>\n<hr>\n<h2><a name=\"p-24116-h-51-layer-1-core-verifier-syntax-17\" class=\"anchor\" href=\"#p-24116-h-51-layer-1-core-verifier-syntax-17\" aria-label=\"Heading link\"></a>5.1 Layer 1: Core Verifier Syntax</h2>\n<p>Core syntax is small, stable, and directly tied to the Cell verifier model.</p>\n<p>Examples:</p>\n<pre><code class=\"lang-plaintext\">action input -&gt; output\nwhere\nmove input.state: A -&gt; output.state: B\nflow\nrequire expr\ncreate output = T { ... }\nconsume\ndestroy\nread / protected / witness / lock_args\n</code></pre>\n<p>These are the verifier calculus.</p>\n<p>They should remain minimal and explicit.</p>\n<hr>\n<h2><a name=\"p-24116-h-52-layer-2-local-explicit-sugar-18\" class=\"anchor\" href=\"#p-24116-h-52-layer-2-local-explicit-sugar-18\" aria-label=\"Heading link\"></a>5.2 Layer 2: Local Explicit Sugar</h2>\n<p>Local sugar may enter the language if it keeps all safety facts visible.</p>\n<p>0.13.1 local sugar:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">preserve output from input {\n    field\n    field\n}\n</code></pre>\n<p>and:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require {\n    expr\n    expr\n}\n</code></pre>\n<p>These are acceptable because they remain local and expandable.</p>\n<hr>\n<h2><a name=\"p-24116-h-53-layer-3-standard-library-advanced-patterns-19\" class=\"anchor\" href=\"#p-24116-h-53-layer-3-standard-library-advanced-patterns-19\" aria-label=\"Heading link\"></a>5.3 Layer 3: Standard-Library Advanced Patterns</h2>\n<p>More advanced protocol concepts should not enter core syntax immediately.</p>\n<p>Examples:</p>\n<pre><code class=\"lang-plaintext\">conserve\npreserve_lock\npreserve_type\npreserve_capacity\nclaim helpers\nsettle helpers\ntransfer helpers\ncapacity accounting helpers\nreceipt redemption helpers\n</code></pre>\n<p>These should first live in standard-library categories such as:</p>\n<pre><code class=\"lang-plaintext\">std::cell\nstd::accounting\nstd::receipt\nstd::lifecycle\nstd::ckb\n</code></pre>\n<p>This makes the user mental model clear:</p>\n<pre><code class=\"lang-plaintext\">core syntax = verifier calculus\nstdlib helper = typed sugar / audit pattern\n</code></pre>\n<p>For example:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require std::cell::same_lock(output, input)\nrequire std::cell::same_type(output, input)\nrequire std::accounting::conserved(input.amount, [left.amount, right.amount])\n</code></pre>\n<p>Every advanced standard-library primitive should have a canonical expansion into core CellScript.</p>\n<hr>\n<h2><a name=\"p-24116-h-54-layer-4-non-core-avoided-features-20\" class=\"anchor\" href=\"#p-24116-h-54-layer-4-non-core-avoided-features-20\" aria-label=\"Heading link\"></a>5.4 Layer 4: Non-Core / Avoided Features</h2>\n<p>The following should remain outside 0.13.1:</p>\n<pre><code class=\"lang-plaintext\">general policy primitive\nnamed reusable require blocks\nreplace / replaces\npreserve all\npreserve except\nimplicit transfer magic\ngeneral settle magic\ncapacity conservation sugar\ncross-module proof policy imports\n</code></pre>\n<p>Reason:</p>\n<p>These features can hide proof obligations, lengthen audit paths, or recreate the ambiguity that <code>replace</code> was removed to avoid.</p>\n<hr>\n<h1><a name=\"p-24116-h-6-desugaring-requirements-21\" class=\"anchor\" href=\"#p-24116-h-6-desugaring-requirements-21\" aria-label=\"Heading link\"></a>6. Desugaring Requirements</h1>\n<p>0.13.1 should define canonical expansion rules.</p>\n<hr>\n<h2><a name=\"p-24116-h-61-preserve-22\" class=\"anchor\" href=\"#p-24116-h-61-preserve-22\" aria-label=\"Heading link\"></a>6.1 <code>preserve</code></h2>\n<p>Source:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">preserve output from input {\n    seller\n    price\n    payment_symbol\n}\n</code></pre>\n<p>Canonical expansion:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require output.seller == input.seller\nrequire output.price == input.price\nrequire output.payment_symbol == input.payment_symbol\n</code></pre>\n<hr>\n<h2><a name=\"p-24116-h-62-require-block-23\" class=\"anchor\" href=\"#p-24116-h-62-require-block-23\" aria-label=\"Heading link\"></a>6.2 <code>require</code> Block</h2>\n<p>Source:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require {\n    payment.amount == input.price\n    payment.symbol == input.payment_symbol\n}\n</code></pre>\n<p>Canonical expansion:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">require payment.amount == input.price\nrequire payment.symbol == input.payment_symbol\n</code></pre>\n<hr>\n<h1><a name=\"p-24116-h-7-example-updated-0131-style-24\" class=\"anchor\" href=\"#p-24116-h-7-example-updated-0131-style-24\" aria-label=\"Heading link\"></a>7. Example: Updated 0.13.1 Style</h1>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">enum OfferState {\n    Created,\n    Live,\n    Filled,\n    Cancelled,\n}\n\nresource Offer has store {\n    state: OfferState\n    seller: Address\n    buyer: Address\n    price: u64\n    payment_symbol: [u8; 8]\n}\n\nresource Token has store, destroy {\n    amount: u64\n    symbol: [u8; 8]\n}\n\nflow Offer.state {\n    Created -&gt; Live;\n    Live -&gt; Filled;\n    Live -&gt; Cancelled;\n}\n\naction fill(input: Offer, payment: Token, buyer: Address)\n    -&gt; (output: Offer, seller_payment: Token)\n    move input.state: Live -&gt; output.state: Filled\nwhere\n    preserve output from input {\n        seller\n        price\n        payment_symbol\n    }\n\n    require {\n        payment.amount == input.price\n        payment.symbol == input.payment_symbol\n        output.buyer == buyer\n    }\n\n    consume payment\n\n    create seller_payment = Token {\n        amount: payment.amount,\n        symbol: payment.symbol\n    } with_lock(input.seller)\n</code></pre>\n<p>This keeps the 0.13 action model intact while improving readability.</p>\n<p>The action still clearly shows:</p>\n<pre><code class=\"lang-plaintext\">input evidence\noutput proposal\nstate edge\nfield continuity\npayment validation\ninput fate\noutput construction\n</code></pre>\n<h1><a name=\"p-24116-h-9-final-summary-25\" class=\"anchor\" href=\"#p-24116-h-9-final-summary-25\" aria-label=\"Heading link\"></a>9. Final Summary</h1>\n<p>That is the current plan for the 0.13.1 patch.</p>\n<p>The intention is deliberately modest: keep the 0.13 action model explicit, add only local ergonomics where the desugared form is obvious, and keep higher-level protocol patterns out of core syntax until they have proved themselves in real examples.</p>\n<p>As always, comments are very welcome, especially on the boundary between useful local sugar and abstractions that might make audits harder.</p>\n<p>I would be particularly interested in feedback on:</p>\n<ul>\n<li>whether <code>preserve output from input { ... }</code> feels clear enough as field-preservation sugar;</li>\n<li>whether anonymous <code>require { ... }</code> blocks improve readability without implying a new proof abstraction;</li>\n<li>whether advanced primitives such as <code>conserve</code>, <code>preserve_lock</code>, <code>claim</code>, <code>settle</code>, or <code>transfer</code> are better kept in standard-library categories rather than core syntax.</li>\n</ul>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    },
    {
      "topic_id": 10136,
      "title": "Building CKB PoP: a reusable participation primitive on CKB",
      "slug": "building-ckb-pop-a-reusable-participation-primitive-on-ckb",
      "url": "https://talk.nervos.org/t/building-ckb-pop-a-reusable-participation-primitive-on-ckb/10136",
      "created_at": "2026-03-29T14:53:12.991000+00:00",
      "last_posted_at": "2026-05-02T12:43:18.761000+00:00",
      "category_id": 32,
      "tags": [
        "CKB",
        "NFT",
        "dapp"
      ],
      "posters": [
        "Original Poster, Most Recent Poster",
        "Frequent Poster",
        "Frequent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24115,
          "post_number": 6,
          "topic_id": 10136,
          "topic_title": "Building CKB PoP: a reusable participation primitive on CKB",
          "topic_slug": "building-ckb-pop-a-reusable-participation-primitive-on-ckb",
          "author": "RobaireTH",
          "created_at": "2026-05-02T12:43:18.761000+00:00",
          "updated_at": "2026-05-02T12:43:18.761000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/building-ckb-pop-a-reusable-participation-primitive-on-ckb/10136/6",
          "content_text": "Over the last few days, I have completed a thorough investigation and fix for several critical bugs across the ckb-pop and ckb-pop-cli repositories. I tried to ensure protocol consistency and restore core functionality that was previously broken.\nKey Bug Fixes & Improvements\nConfirmed Bugs\nThe dob-badge on-chain contract expects 60-byte script args (including a unique 20-byte Type ID), but the CLI was only providing 40 bytes. This caused all CLI-initiated mints to fail.\nThe open-window command signed a window proof but never registered it with the backend. This meant HMACs generated by the CLI could never be verified by the backend when an attendee tried to claim a badge.\nThe frontend “Live QR” kiosk was using a naive CKB-PoP-QR message format that wasn’t supported by the backend, and it was displaying QR codes containing raw signatures instead of time-rotating HMACs.\nFixes\nUpdated badge args to 60 bytes to match the on-chain dob-badge contract requirements.\nUpdated the Browser Signer to automatically compute the truncated Type ID (blake2b hash of the first input) and inject it into the transaction before signing, ensuring the on-chain uniqueness constraint is met.\nAdded backend window registration to the open-window command.\nAligned the ckb-presence library with the backend’s CKB-PoP-Window message format\nRefactored LiveQrComponent to register the attendance window and poll the backend for standard rotating QR codes, ensuring web-hosted kiosks are fully compatible with the backend and attendee apps.\nUpdated the badgeExistsHint in the frontend to query the backend’s badge-holders endpoint. This provides a reliable check for existing badges, which is otherwise difficult via indexers due to the unique Type ID prefix in the script args.\nDiff: CKB PoP | CKB PoP CLI",
          "content_html": "<p>Over the last few days, I have completed a thorough investigation and fix for several critical bugs across the ckb-pop and ckb-pop-cli repositories. I tried to ensure protocol consistency and restore core functionality that was previously broken.</p>\n<h3><a name=\"p-24115-key-bug-fixes-improvements-1\" class=\"anchor\" href=\"#p-24115-key-bug-fixes-improvements-1\" aria-label=\"Heading link\"></a><strong>Key Bug Fixes &amp; Improvements</strong></h3>\n<h4><a name=\"p-24115-confirmed-bugs-2\" class=\"anchor\" href=\"#p-24115-confirmed-bugs-2\" aria-label=\"Heading link\"></a><strong>Confirmed</strong> <strong>Bugs</strong></h4>\n<ol>\n<li>\n<p>The dob-badge on-chain contract expects 60-byte script args (including a unique 20-byte Type ID), but the CLI was only providing 40 bytes. This caused all CLI-initiated mints to fail.</p>\n</li>\n<li>\n<p>The open-window command signed a window proof but never registered it with the backend. This meant HMACs generated by the CLI could never be verified by the backend when an attendee tried to claim a badge.</p>\n</li>\n<li>\n<p>The frontend “Live QR” kiosk was using a naive CKB-PoP-QR message format that wasn’t supported by the backend, and it was displaying QR codes containing raw signatures instead of time-rotating HMACs.</p>\n</li>\n</ol>\n<h4><a name=\"p-24115-fixes-3\" class=\"anchor\" href=\"#p-24115-fixes-3\" aria-label=\"Heading link\"></a><strong>Fixes</strong></h4>\n<ol>\n<li>Updated badge args to 60 bytes to match the on-chain dob-badge contract requirements.</li>\n<li>Updated the Browser Signer to automatically compute the truncated Type ID (blake2b hash of the first input) and inject it into the transaction before signing, ensuring the on-chain uniqueness constraint is met.</li>\n<li>Added backend window registration to the open-window command.</li>\n<li>Aligned the ckb-presence library with the backend’s CKB-PoP-Window message format</li>\n<li>Refactored LiveQrComponent to register the attendance window and poll the backend for standard rotating QR codes, ensuring web-hosted kiosks are fully compatible with the backend and attendee apps.</li>\n<li>Updated the badgeExistsHint in the frontend to query the backend’s badge-holders endpoint. This provides a reliable check for existing badges, which is otherwise difficult via indexers due to the unique Type ID prefix in the script args.</li>\n</ol>\n<p><strong>Diff</strong>: <a href=\"https://github.com/RobaireTH/ckb-pop/commit/f2b761f90e5122b514c72a2a7d33b42697626e3e\" rel=\"noopener nofollow ugc\">CKB PoP</a> | <a href=\"https://github.com/RobaireTH/ckb-pop-cli/commit/71827df035bab2e87a9f8eca968f37d7d02a2098\" rel=\"noopener nofollow ugc\">CKB PoP CLI</a></p>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    },
    {
      "topic_id": 10226,
      "title": "Multi-Model Allocation Guide for Complex Tasks",
      "slug": "multi-model-allocation-guide-for-complex-tasks",
      "url": "https://talk.nervos.org/t/multi-model-allocation-guide-for-complex-tasks/10226",
      "created_at": "2026-05-02T05:44:50.813000+00:00",
      "last_posted_at": "2026-05-02T12:34:46.323000+00:00",
      "category_id": 31,
      "tags": [
        "AI"
      ],
      "posters": [
        "Original Poster",
        "Most Recent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24111,
          "post_number": 1,
          "topic_id": 10226,
          "topic_title": "Multi-Model Allocation Guide for Complex Tasks",
          "topic_slug": "multi-model-allocation-guide-for-complex-tasks",
          "author": "zz_tovarishch",
          "created_at": "2026-05-02T05:44:50.862000+00:00",
          "updated_at": "2026-05-02T05:44:50.862000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/multi-model-allocation-guide-for-complex-tasks/10226/1",
          "content_text": "For routing complex tasks across multiple AI models, I noticed that benchmark-based allocation (HLE, GPQA, IFBench, etc.) only explains part of the story. Each model defaults to a distinct cognitive register when handed the same task. Therefore, have this guide.\nClaude Opus 4.7 is the lead and coordinator. Highest non-hallucination rate and 1M context. Methodology judgment, long-document reading, integration, final draft.\nCodex (GPT-5.5) is the hard-reasoning specialist. Highest raw reasoning scores, most surgical precision in rewrites and cross-section consistency. Never let it independently produce factual claims.\nGemini 3.1 Pro is the knowledge anchor. Highest Omniscience and IFBench. Default first-stop for knowledge queries, figure extraction, plus reviewer-mind sniff tests.\nKimi K2.6 is the interactive ping-pong specialist with Sinophone audit. About 1 second first-chunk latency. Principle-and-category thinking, non-Western prior-work coverage.\nSent the guide to your main AI, then it dispatches all three external models in parallel, then has the lead integrate by using Kimi’s principle to structure the rewrite, Codex’s phrasing for the actual text, and Gemini’s heuristic for the final sniff test. Hard stop-doing rules cover the failure modes (Codex hallucinations, Gemini style-drift, Kimi context truncation, Claude format-drift).",
          "content_html": "<p>For routing complex tasks across multiple AI models, I noticed that benchmark-based allocation (HLE, GPQA, IFBench, etc.) only explains part of the story. Each model defaults to a distinct cognitive register when handed the same task. Therefore, have this <a href=\"https://github.com/kydchen/AI-related/blob/main/Guidance/multimodel_research_guide.md\">guide</a>.</p>\n<p>Claude Opus 4.7 is the lead and coordinator. Highest non-hallucination rate and 1M context. Methodology judgment, long-document reading, integration, final draft.</p>\n<p>Codex (GPT-5.5) is the hard-reasoning specialist. Highest raw reasoning scores, most surgical precision in rewrites and cross-section consistency. Never let it independently produce factual claims.</p>\n<p>Gemini 3.1 Pro is the knowledge anchor. Highest Omniscience and IFBench. Default first-stop for knowledge queries, figure extraction, plus reviewer-mind sniff tests.</p>\n<p>Kimi K2.6 is the interactive ping-pong specialist with Sinophone audit. About 1 second first-chunk latency. Principle-and-category thinking, non-Western prior-work coverage.</p>\n<p>Sent the guide to your main AI, then it dispatches all three external models in parallel, then has the lead integrate by using Kimi’s principle to structure the rewrite, Codex’s phrasing for the actual text, and Gemini’s heuristic for the final sniff test. Hard stop-doing rules cover the failure modes (Codex hallucinations, Gemini style-drift, Kimi context truncation, Claude format-drift).</p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24114,
          "post_number": 2,
          "topic_id": 10226,
          "topic_title": "Multi-Model Allocation Guide for Complex Tasks",
          "topic_slug": "multi-model-allocation-guide-for-complex-tasks",
          "author": "ArthurZhang",
          "created_at": "2026-05-02T12:34:46.323000+00:00",
          "updated_at": "2026-05-02T12:35:14.666000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/multi-model-allocation-guide-for-complex-tasks/10226/2",
          "content_text": "Nice sum-up.\nOne model I would also add to this routing map is GLM 5.1, especially for code review and engineering-risk audit.",
          "content_html": "<p>Nice sum-up.<br>\nOne model I would also add to this routing map is <strong>GLM 5.1</strong>, especially for code review and engineering-risk audit.</p>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    },
    {
      "topic_id": 10008,
      "title": "Spark Program | Ckb-probe: Deep Observability Tool for CKB Nodes Based on Aya Kernel eBPF/ckb-probe：基于 Aya 内核 eBPF 的 CKB 节点深度可观测性工具",
      "slug": "spark-program-ckb-probe-deep-observability-tool-for-ckb-nodes-based-on-aya-kernel-ebpf-ckb-probe-aya-ebpf-ckb",
      "url": "https://talk.nervos.org/t/spark-program-ckb-probe-deep-observability-tool-for-ckb-nodes-based-on-aya-kernel-ebpf-ckb-probe-aya-ebpf-ckb/10008",
      "created_at": "2026-02-26T07:25:51.446000+00:00",
      "last_posted_at": "2026-05-02T08:19:48.293000+00:00",
      "category_id": 49,
      "tags": [
        "In-Progress",
        "Spark-Program"
      ],
      "posters": [
        "Original Poster, Most Recent Poster",
        "Frequent Poster",
        "Frequent Poster",
        "Frequent Poster",
        "Frequent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24112,
          "post_number": 51,
          "topic_id": 10008,
          "topic_title": "Spark Program | Ckb-probe: Deep Observability Tool for CKB Nodes Based on Aya Kernel eBPF/ckb-probe：基于 Aya 内核 eBPF 的 CKB 节点深度可观测性工具",
          "topic_slug": "spark-program-ckb-probe-deep-observability-tool-for-ckb-nodes-based-on-aya-kernel-ebpf-ckb-probe-aya-ebpf-ckb",
          "author": "clair",
          "created_at": "2026-05-02T08:17:46.141000+00:00",
          "updated_at": "2026-05-02T08:17:46.141000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/spark-program-ckb-probe-deep-observability-tool-for-ckb-nodes-based-on-aya-kernel-ebpf-ckb-probe-aya-ebpf-ckb/10008/51",
          "content_text": "CKB-Probe 演示流程说明\n范围：仅限 CKB 测试网\n本文档覆盖 ckb-probe 的五个核心演示步骤，每步附完整终端输出、关键命令说明和输出解读。\n所有输出均为真实运行数据（2026-05-02，CKB v0.204.0 测试网节点）。\n调整说明\n本文档替代原计划的演示视频。文字报告在以下方面对评审者更为友好：\n评审者可以直接复制报告中的命令进行复现，不需要反复拖动视频进度条\n终端输出配合文字解读比视频旁白更容易精确定位到具体的输出字段和数值\n报告本身可以作为项目文档的一部分长期保留，便于后续版本更新时同步修改\n视频一旦录制后修改成本较高，而文档可以随项目迭代\n前置条件\n# 系统要求\n# - Linux 内核 >= 5.8 (BTF 支持)\n# - root 权限 (eBPF 需要 CAP_BPF + CAP_SYS_ADMIN)\n# - CKB 测试网节点运行中\n# Docker 方式运行 (推荐)\ndocker run --rm --privileged --pid host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /path/to/ckb-testnet:/data \\\n-v /path/to/ckb:/usr/local/bin/ckb:ro \\\nckb-probe:latest <command>\n# 或者直接在宿主机运行 (需要 root)\nsudo ckb-probe <command>\n步骤 1: 环境检查与 eBPF 验证\n目的： 验证 eBPF 环境就绪、CKB 二进制可探测、所有 uprobe/kprobe/tracepoint 可挂载。\n命令：\nsudo ckb-probe check --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb)\n完整终端输出：\n╔══════════════════════════════════════════════════════════════╗\n║ ckb-probe environment check ║\n╠══════════════════════════════════════════════════════════════╣\n✅ Kernel version 6.8.0-106-generic (need >= 5.8)\n✅ BPF config BPF=y SYSCALL=y JIT=y\n✅ BTF support /sys/kernel/btf/vmlinux exists\n✅ Permissions running as root\n✅ bpf() syscall available\n✅ uprobe support /sys/kernel/debug/tracing/uprobe_events exists\n✅ CKB process 1 instance(s), pid=2349824\n✅ CKB symbols 2/3 key symbols found (symtab)\n╚══════════════════════════════════════════════════════════════╝\nResult: 8/8 checks passed\n🎉 All checks passed!\n╔═════���════════════════════════════════════════════════════════╗\n║ ckb-probe eBPF validation ║\n╠══════════════════════════════════════════════════════════════╣\n✅ ── uprobe latency ── entry/return pair attach test\n✅ rocksdb_get_pinned_cf entry + return attached\n✅ rocksdb_put entry + return attached\n✅ rocksdb_write entry + return attached\n❌ rocksdb_delete symbol not in binary (expected)\n✅ rocksdb_create_iterator_cf entry + return attached\n❌ rocksdb_multi_get_cf symbol not in binary (expected)\n✅ ── uprobe Tier 1 ── all 19 Tier 1 symbol attach test\n✅ rocksdb_get symbol found, uprobe-attachable\n✅ rocksdb_get_pinned symbol found, uprobe-attachable\n✅ rocksdb_get_pinned_cf symbol found, uprobe-attachable\n✅ rocksdb_put symbol found, uprobe-attachable\n✅ rocksdb_put_cf symbol found, uprobe-attachable\n✅ rocksdb_write symbol found, uprobe-attachable\n❌ rocksdb_delete not found in binary\n❌ rocksdb_delete_cf not found in binary\n❌ rocksdb_multi_get_cf not found in binary\n✅ rocksdb_transaction_put_cf symbol found, uprobe-attachable\n✅ rocksdb_transaction_delete_cf symbol found, uprobe-attachable\n❌ rocksdb_transaction_get_cf not found in binary\n✅ rocksdb_transaction_commit symbol found, uprobe-attachable\n✅ rocksdb_optimistictransaction_begin symbol found, uprobe-attachable\n✅ rocksdb_create_iterator_cf symbol found, uprobe-attachable\n✅ rocksdb_iter_seek symbol found, uprobe-attachable\n✅ rocksdb_iter_seek_to_first symbol found, uprobe-attachable\n✅ rocksdb_iter_next symbol found, uprobe-attachable\n✅ rocksdb_iter_destroy symbol found, uprobe-attachable\n✅ uprobe summary latency pairs: 4/6, Tier 1 symbols: 15/19\n✅ kprobe tcp_sendmsg_entry attached to tcp_sendmsg\n✅ kprobe tcp_sendmsg_return attached to tcp_sendmsg\n✅ kprobe tcp_recvmsg_entry attached to tcp_recvmsg\n✅ kprobe tcp_recvmsg_return attached to tcp_recvmsg\n✅ tracepoint sys_enter attached to raw_syscalls/sys_enter\n╚══════════════════════════════════════════════════════════════╝\nResult: 27/33 checks passed\n⏳ Collecting live events for 3 seconds...\n[syscall] pid=2349824 tid=808096 nr=232 (epoll_wait)\n[uprobe] pid=2349824 tid=2351140 func=get_pinned_cf latency=45.2μs\n[uprobe] pid=2349824 tid=2351140 func=get_pinned_cf latency=14.5μs\n[uprobe] pid=2349824 tid=2351140 func=get_pinned_cf latency=5.3μs\n[uprobe] pid=2349824 tid=2351140 func=get_pinned_cf latency=6.0μs\n[uprobe] pid=2349824 tid=2351140 func=get_pinned_cf latency=4.5μs\n[tcp] pid=2349824 tid=740351 dir=RX bytes=705\n[tcp] pid=2349824 tid=808096 dir=TX bytes=705\n📊 Captured 264 uprobe, 40 tcp, 438 syscall events in 3s\n解读：\n环境检查 8/8 全部通过：内核 6.8.0 满足 >= 5.8 要求，BTF 可用，root 权限，bpf() 系统调用可用\neBPF 验证 27/33 通过：4 个 uprobe 延迟对（GET/PUT/WRITE/ITER）成功挂载，15/19 个 Tier 1 符号可用，4 个未找到的符号（delete/multi_get/transaction_get_cf）是 CKB 未使用的 RocksDB API，属于预期缺失\nkprobe/tracepoint 全部成功：tcp_sendmsg/tcp_recvmsg 网络探针 + raw_syscalls 系统调用追踪\n实时事件采集验证：3 秒内捕获 264 个 uprobe 事件 + 40 个 TCP 事件 + 438 个 syscall 事件，证明数据通道正常\n步骤 2: 符号分析\n目的： 全面分析 CKB 二进制中的 RocksDB 符号，评估 uprobe 覆盖率。\n命令：\nckb-probe symbols /root/ckb-testnet/ckb\n完整终端输出：\n════════════════════════════════════════════════════════════════════\nCKB Binary Symbol Analysis Report\nBinary: /root/ckb-testnet/ckb (65.0 MB)\nFormat: ELF 64-bit x86_64\n════════════════════════════════════════════════════════════════════\n── ELF Overview ────────────────────────────────────────\n.symtab: ✅ Present (153057 symbols)\n.dynsym: ✅ Present (511 symbols)\nDWARF: ❌ Not found\nStrip status: debuginfo-stripped (.symtab retained)\n── RocksDB Linkage ─────────────────────────────────────\nMethod: Static (bundled into CKB binary)\nEvidence: No librocksdb.so in dynamic deps; 155 rocksdb_* in .symtab\nAssessment: ✅ Ideal — C API symbols embedded in binary\n── Dynamic Dependencies ────────────────────────────────\nlibstdc++.so.6 libgcc_s.so.1 libm.so.6\nlibc.so.6 ld-linux-x86-64.so.2\n── [Tier 1] Directly uprobe-attachable (extern \"C\", stable) ──\n✅ rocksdb_get 0x021e3330 (318 B)\n✅ rocksdb_get_cf 0x021e34a0 (215 B)\n✅ rocksdb_get_pinned 0x021e4b20 (427 B)\n✅ rocksdb_get_pinned_cf 0x021e4d00 (379 B)\n✅ rocksdb_put 0x021e30a0 (105 B)\n✅ rocksdb_put_cf 0x021e3120 (240 B)\n✅ rocksdb_write 0x021e3230 (208 B)\n✅ rocksdb_transaction_put_cf 0x021e4770 (113 B)\n✅ rocksdb_transaction_delete_cf 0x021e4800 (101 B)\n✅ rocksdb_transaction_commit 0x021e42f0 (71 B)\n✅ rocksdb_optimistictransaction_begin 0x021e4a50 (99 B)\n✅ rocksdb_create_iterator_cf 0x021e3670 (167 B)\n✅ rocksdb_iter_seek 0x021e3b30 (30 B)\n✅ rocksdb_iter_seek_to_first 0x021e3b10 (9 B)\n✅ rocksdb_iter_next 0x021e3b70 (9 B)\n✅ rocksdb_iter_destroy 0x021e3ae0 (32 B)\n→ 16 / 20 tracked targets found\n── [Tier 2] Possibly available (Rust mangled, version-bound) ──\n⚠️ ckb_network::network::NetworkService::start\n⚠️ ckb_sync::synchronizer::block_process::BlockProcess::execute\n⚠️ ckb_sync::synchronizer::headers_process::HeadersProcess::execute\n⚠️ ckb_chain::chain_controller::ChainController::asynchronous_process_remote_block\n⚠️ ckb_store::transaction::StoreTransaction::attach_block\n⚠️ ckb_store::transaction::StoreTransaction::insert_block\n⚠️ ckb_store::transaction::StoreTransaction::commit\n⚠️ ckb_db::db::RocksDB::get_pinned\n⚠️ ckb_db::db::RocksDB::get_pinned_default\n... (11 / 21 tracked targets found)\n── [Tier 3] Unavailable (inlined / stripped / crate-internal) ──\n❌ ckb_network::protocols::CKBHandler::received — not found (likely inlined)\n❌ ckb_chain::chain_service::ChainService::process_block — not found (likely inlined)\n❌ ckb_store::db::ChainDB::get_block — not found (likely inlined)\n... (19 tracked functions not found)\n── Summary ─────────────────────────────────────────────\nTier 1: 16 / 20 ( 80%) partial coverage ⚠️\nTier 2: 11 / 21 ( 52%) available in this binary\nTier 3: 19 tracked functions not found\nTotal function symbols: 86852\nTotal RocksDB C API symbols: 155\n════════════════════════════════════════════════════════════════════\n解读：\nTier 1 (C API) — 16/20 找到（80%），这些是 extern \"C\" 符号，跨 CKB 版本稳定，是 ckb-probe 的核心探测点\nRocksDB 静态链接 — 155 个 rocksdb_* 符号直接嵌入 CKB 二进制，无需额外的 .so 文件\nTier 2 (Rust mangled) — 11/21 找到，这些 Rust 函数名含编译哈希，不同版本可能变化\nTier 3 (inlined) — 19 个预期缺失，因为编译器内联优化消除了这些函数入口\n步骤 3: 正常同步期间的实时 RocksDB 监控\n目的： 在 CKB 测试网节点正常运行期间，实时展示五类 RocksDB 操作的延迟、吞吐和延迟分布。\n3a. 统计表格模式\n命令：\nsudo ckb-probe rocksdb --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb) --interval 5\n终端输出：\n╭───────────────── CKB RocksDB Monitor (PID: 2349824) ─────────────────╮\n│ Uptime: 00:00:05 Sampling: 5s Node: CKB v0.204.0 │\n├────────────┬───────┬──────────┬──────────┬──────────┬────────────────┤\n│ Operation │ QPS │ Avg(μs) │ P50(μs) │ P99(μs) │ Bytes/s │\n├────────────┼───────┼──────────┼──────────┼──────────┼────────────────┤\n│ GET │ 93 │ 23.8 │ 6.1 │ 196.6 │ 5.5 KB/s │\n│ PUT │ 8 │ 6.7 │ 6.1 │ 24.6 │ 624 B/s │\n│ WRITE │ 0 │ 43.1 │ 49.2 │ 49.2 │ — │\n│ ITER_NEW │ 1 │ 38.6 │ 49.2 │ 98.3 │ — │\n│ TXN_COMMIT │ 1 │ 326.7 │ 393.2 │ 393.2 │ 624 B/s │\n╰────────────┴───────┴──────────┴──────────┴──────────┴────────────────╯\nStatus: ⏳ Warming up — Collecting baseline (295s remaining).\n╭───────────────── CKB RocksDB Monitor (PID: 2349824) ─────────────────╮\n│ Uptime: 00:00:10 Sampling: 5s Node: CKB v0.204.0 │\n├────────────┬───────┬──────────┬──────────┬──────────┬────────────────┤\n│ Operation │ QPS │ Avg(μs) │ P50(μs) │ P99(μs) │ Bytes/s │\n├────────────┼───────┼──────────┼──────────┼──────────┼────────────────┤\n│ GET │ 177 │ 411.6 │ 12.3 │ 12582.9 │ 21.5 KB/s │\n│ PUT │ 0 │ 0.0 │ 0.0 │ 0.0 │ 0 B/s │\n│ WRITE │ 0 │ 0.0 │ 0.0 │ 0.0 │ — │\n│ ITER_NEW │ 0 │ 0.0 │ 0.0 │ 0.0 │ — │\n│ TXN_COMMIT │ 0 │ 0.0 │ 0.0 │ 0.0 │ 0 B/s │\n╰────────────┴───────┴──────────┴──────────┴──────────┴────────────────╯\nStatus: ⏳ Warming up — Collecting baseline (290s remaining).\n3b. 延迟分布直方图模式\n命令：\nsudo ckb-probe rocksdb --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb) --histogram --interval 5\n终端输出（表格下方附加直方图）：\nGET latency distribution:\n2μs │████ 22\n4μs │████████████████████████████████████████ 369\n8μs │███████████████████ 182\n16μs │██████████████████ 213\n32μs │██████████ 46\n65μs │██ 6\nPUT latency distribution:\n2μs │██████ 3\n4μs │████████████████████████████████████████ 10\n8μs │████ 2\n16μs │██████ 3\n32μs │██ 1\nWRITE latency distribution:\n32μs │████████████████████████████████████████ 1\nITER_NEW latency distribution:\n16μs │████████████████████████████████████████ 2\n32μs │████████████████████████████████████████ 2\nTXN_COMMIT latency distribution:\n65μs │████████████████████ 1\n262μs │████████████████████████████████████████ 2\n解读：\nGET 呈长尾分布：主体在 2~32us（缓存命中），少量尾部延迟由磁盘 I/O 引起\nPUT 集中在 4~16us，单次写入非常轻量\nTXN_COMMIT 在 65~262us 区间，反映 WAL 写入开销\n直方图数据来自 eBPF 内核态 per-CPU 计数器，零采样开销\n步骤 4: 慢操作捕获\n目的： 实时捕获超过阈值的 RocksDB 操作，展示每个慢操作的精确延迟、数据大小和 BPF 事件丢失率。\n命令：\nsudo ckb-probe rocksdb --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb) \\\n--slow --threshold 1000 --interval 5\n终端输出：\n╭───────────────── Slow Operations (threshold: 1000μs) ──────────────────╮\n│ Timestamp │ Op │ Latency │ Size │ Note │\n├───────────────┼────────────┼───────────┼──────────┼────────────────────┤\n│ 57:21.976 │ GET │ 8,162μs │ 125 B │ │\n│ 57:21.986 │ GET │ 9,389μs │ 240 B │ │\n│ 57:21.992 │ GET │ 5,346μs │ 125 B │ │\n│ 57:21.998 │ GET │ 6,167μs │ 8 B │ │\n│ 57:22.004 │ GET │ 5,484μs │ 173 B │ │\n│ 57:22.007 │ GET │ 3,084μs │ 8 B │ │\n╰───────────────┴────────────┴───────────┴──────────┴────────────────────╯\nShowing 8 of 13 slow operations in last 5s.\nBPF event loss: 0 / 13 attempted (0.0000%)\n╭───────────────── Slow Operations (threshold: 1000μs) ──────────────────╮\n│ Timestamp │ Op │ Latency │ Size │ Note │\n├───────────────┼────────────┼───────────┼──────────┼────────────────────┤\n│ 57:29.099 │ GET │ 7,207μs │ 8 B │ │\n│ 57:29.104 │ GET │ 5,223μs │ 32 B │ │\n│ 57:29.107 │ GET │ 2,432μs │ 240 B │ │\n│ 57:29.115 │ GET │ 8,238μs │ 101 B │ │\n│ 57:29.127 │ GET │ 11,631μs │ 32 B │ │\n│ 57:29.130 │ GET │ 3,230μs │ 240 B │ │\n│ 57:29.134 │ GET │ 4,002μs │ 101 B │ │\n│ 57:29.137 │ GET │ 2,946μs │ 8 B │ │\n╰───────────────┴────────────┴───────────┴──────────┴────────────────────╯\nShowing 8 of 32 slow operations in last 10s.\nBPF event loss: 0 / 32 attempted (0.0000%)\n解读：\n仅超过 1000us (1ms) 的操作被捕获，常态下对系统零开销\n慢操作全部为 GET，延迟在 2~11ms，由 RocksDB block cache miss 触发磁盘读取导致\nBPF event loss: 0 / 32 (0.0000%) — RingBuf 数据通道零丢失\nSize 列显示该操作读写的数据大小（8B = key, 32~240B = value）\n步骤 5: JSON 导出\n目的： 展示机器可读的 JSON 输出格式，适合下游监控管线和数据分析。\n5a. 标准 JSON 输出\n命令：\nsudo ckb-probe rocksdb --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb) \\\n--json --interval 5\n终端输出（单个采样周期）：\n{\n\"anomalies\": [],\n\"operations\": {\n\"GET\": {\n\"avg_us\": 19.71,\n\"bytes_per_sec\": 1673,\n\"p50_us\": 12.29,\n\"p99_us\": 98.3,\n\"qps\": 22\n},\n\"ITER_NEW\": {\n\"avg_us\": 0.0,\n\"bytes_per_sec\": null,\n\"p50_us\": 0.0,\n\"p99_us\": 0.0,\n\"qps\": 0\n},\n\"PUT\": {\n\"avg_us\": 0.0,\n\"bytes_per_sec\": 0,\n\"p50_us\": 0.0,\n\"p99_us\": 0.0,\n\"qps\": 0\n},\n\"TXN_COMMIT\": {\n\"avg_us\": 0.0,\n\"bytes_per_sec\": 0,\n\"p50_us\": 0.0,\n\"p99_us\": 0.0,\n\"qps\": 0\n},\n\"WRITE\": {\n\"avg_us\": 0.0,\n\"bytes_per_sec\": null,\n\"p50_us\": 0.0,\n\"p99_us\": 0.0,\n\"qps\": 0\n}\n},\n\"pid\": 2349824,\n\"timestamp\": \"2026-05-02T07:31:41Z\",\n\"uptime_secs\": 0\n}\n5b. JSON + 直方图融合输出\n命令：\nsudo ckb-probe rocksdb --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb) \\\n--json --histogram --interval 5\n终端输出（单个采样周期，含 histogram 字段）：\n{\n\"anomalies\": [],\n\"operations\": {\n\"GET\": {\n\"avg_us\": 244.69,\n\"bytes_per_sec\": 11803,\n\"histogram\": [\n{ \"count\": 25, \"ge_us\": 4.1 },\n{ \"count\": 5, \"ge_us\": 8.19 },\n{ \"count\": 6, \"ge_us\": 16.38 }\n],\n\"p50_us\": 12.29,\n\"p99_us\": 12582.91,\n\"qps\": 116\n},\n\"PUT\": {\n\"avg_us\": 6.26,\n\"bytes_per_sec\": 1439,\n\"histogram\": [\n{ \"count\": 10, \"ge_us\": 4.1 },\n{ \"count\": 2, \"ge_us\": 8.19 },\n{ \"count\": 3, \"ge_us\": 16.38 }\n],\n\"p50_us\": 6.14,\n\"p99_us\": 49.15,\n\"qps\": 10\n}\n},\n\"pid\": 2349824,\n\"timestamp\": \"2026-05-02T07:32:11Z\",\n\"uptime_secs\": 5\n}\n5c. JSON 字段说明\n字段\n类型\n说明\ntimestamp\nstring\nISO 8601 UTC 时间戳\npid\nnumber\n目标 CKB 进程 PID\nuptime_secs\nnumber\nckb-probe 运行时长（秒）\noperations\nobject\n五个 RocksDB 操作的实时指标\noperations.*.qps\nnumber\n每秒操作数\noperations.*.avg_us\nnumber\n平均延迟（微秒）\noperations.*.p50_us\nnumber\nP50 延迟（微秒，log2 直方图插值）\noperations.*.p99_us\nnumber\nP99 延迟（微秒，log2 直方图插值）\noperations.*.bytes_per_sec\nnumber / null\n吞吐量（B/s），WRITE/ITER_NEW 为 null\noperations.*.histogram\narray\nlog2 延迟分布（仅 --histogram 时出现）\noperations.*.histogram[].ge_us\nnumber\n桶下界（微秒）\noperations.*.histogram[].count\nnumber\n该桶内的操作数\nanomalies\narray\nEWMA 异常事件（5 分钟 warmup 后启用）\nanomalies.*.trigger\nstring\n触发条件组合：AVG / P99 / CAP\nanomalies.*.multiplier\nnumber\n当前均值 / 基线均值\n附录 A: 48h 稳定性测试结果摘要\n完整报告见 docs/STABILITY-REPORT_zh.md\n#\n指标\n结果\n关键数据\nS-1\n无崩溃\nPASS\n48h 全程无 panic/SIGSEGV\nS-2\n内存稳定\nPASS\nRSS 增长 0.00 MB（预算 5 MB）\nS-3\n无 BPF 错误\nPASS*\n误报（systemd 版本字符串匹配）\nS-4\n重启恢复\nPASS\nCKB 重启后 1 秒重连\n资源使用：Probe CPU P99=0.29%，RSS 稳定 21.4 MB，BPF 事件丢失 0/126,934 (0.0000%)\n附录 B: Case Study 结果摘要\n完整报告见 docs/CASE-STUDY-REPORT_zh.md\nCase 1 (IBD 写入模式): 22 分钟完整 IBD 追赶，GET 主导 (109.7 QPS)，6 个 ITER_NEW 异常事件\nCase 2 (压缩风暴): aggressive 调优下 GET 延迟从 ~200us 飙升至 6,988us (35x)，30 分钟捕获 6,112 个慢操作，零事件丢失\n附录 C: P-1~P-4 性能测试结果摘要\n完整报告见 Week 5 周报\n指标\n结果\n预算\nP-1 CPU 开销\n+2.11% (2h 综合)\n<= 3%\nP-2 RSS\n21.97 MB (稳定)\n<= 50 MB\nP-3 事件丢失\n0/78,353 (0.0000%)\n< 0.1%\nP-4 同步退化\n+0.37% (2h 综合)\n< 1%\n四项全部 PASS。\n运行模式总结\n模式\n命令\n输出格式\n用途\n环境检查\ncheck\n文本\n验证 eBPF 环境和符号可用性\n符号分析\nsymbols\n文本 / JSON\n分析 CKB 二进制符号覆盖率\n实时表格\nrocksdb\nTUI 表格\n实时监控 QPS/延迟/吞吐\n延迟直方图\nrocksdb --histogram\nTUI 直方图\n分析延迟分布特征\n慢操作捕获\nrocksdb --slow\nTUI 列表\n捕获超阈值操作\nJSON 输出\nrocksdb --json\nJSONL\n机器可读，供下游管线消费\nJSON + 直方图\nrocksdb --json --histogram\nJSONL\n含 log2 延迟分布的完整导出\n附录 D: Docker 构建与运行指南\nD.1 构建 Docker 镜像\ncd /root/ckb-probe\ndocker build -f docker/Dockerfile -t ckb-probe:latest .\n构建过程：\nStage 1 (probe-builder)：安装 Rust nightly + clang/llvm + bpf-linker，编译 eBPF 内核程序 + 用户态 CLI + db_bench\nStage 2 (runtime)：Ubuntu 24.04 + 运行时工具，复制编译产物和脚本\n产物镜像约 123 MB\nD.2 通用 Docker 运行模板\n# 基础命令模板（所有 demo / case / perf / stability 通用）\ndocker run --rm \\\n--privileged --pid host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /path/to/ckb-testnet:/data \\\n-v /path/to/ckb:/usr/local/bin/ckb:ro \\\n-v /tmp/output:/tmp/perf-run \\\nckb-probe:latest <command> [args...]\n必需卷挂载说明：\n挂载\n用途\n/sys/kernel/debug\neBPF uprobe/kprobe 需要 debugfs\n/sys/kernel/btf\nBTF 类型信息（内核 >= 5.8）\n/path/to/ckb-testnet:/data\nCKB 链数据目录\n/path/to/ckb:/usr/local/bin/ckb:ro\nCKB 二进制（路径需与宿主机进程 exe 匹配）\n/tmp/output:/tmp/perf-run\n输出目录（报告、日志）\n必需权限：\n--privileged：eBPF 需要 CAP_BPF + CAP_SYS_ADMIN\n--pid host：访问宿主机进程的 PID namespace\nD.3 Docker 内六个 Demo 执行方法与结果\n以下所有命令均在 Docker 容器中执行，CKB 测试网节点运行在宿主机上。\nDemo 1: demo-check（环境检查 + 符号验证）\n命令：\ndocker run --rm --privileged --pid host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /root/ckb-testnet:/data \\\n-v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\nckb-probe:latest demo-check\n实际输出：\n════════════════════════════════════════════════════════════════\ndemo-check — environment + symbol report\n════════════════════════════════════════════════════════════════\n[1/3] running: ckb-probe check\n╔══════════════════════════════════════════════════════════════╗\n║ ckb-probe environment check ║\n╠══════════════════════════════════════════════════════════════╣\n✅ Kernel version 6.8.0-106-generic (need >= 5.8)\n❌ BPF config config not found\n✅ BTF support /sys/kernel/btf/vmlinux exists\n✅ Permissions running as root\n✅ bpf() syscall available\n✅ uprobe support /sys/kernel/debug/tracing/uprobe_events exists\n✅ CKB process 1 instance(s), pid=2349824\n❌ CKB symbols no key rocksdb symbols found\n╚══════════════════════════════════════════════════════════════╝\nResult: 6/8 checks passed\n╔══════════════════════════════════════════════════════════════╗\n║ ckb-probe eBPF validation ║\n╠══════════════════════════════════════════════════════════════╣\n✅ ── uprobe latency ── entry/return pair attach test\n✅ rocksdb_get_pinned_cf entry + return attached\n✅ rocksdb_put entry + return attached\n✅ rocksdb_write entry + return attached\n✅ rocksdb_create_iterator_cf entry + return attached\n✅ uprobe summary latency pairs: 4/6, Tier 1 symbols: 15/19\n✅ kprobe tcp_sendmsg/tcp_recvmsg attached\n✅ tracepoint sys_enter attached to raw_syscalls/sys_enter\n╚══════════════════════════════════════════════════════════════╝\n📊 Captured 264 uprobe, 40 tcp, 438 syscall events in 3s\n注：Docker 容器内 /proc/config.gz 不可用，导致 BPF config 检查失败（），但不影响实际 eBPF 功能。CKB symbols 检查在容器内因路径差异报 ，但 eBPF validation 部分确认了 15/19 个 Tier 1 符号实际可挂载。\nDemo 2: demo-table（实时统计表格）\n命令：\ndocker run --rm --privileged --pid host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /root/ckb-testnet:/data \\\n-v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\nckb-probe:latest demo-table 60\n实际输出：\n╭───────────────── CKB RocksDB Monitor (PID: 2349824) ─────────────────╮\n│ Uptime: 00:00:15 Sampling: 5s Node: CKB v0.204.0 │\n├────────────┬───────┬──────────┬──────────┬──────────┬────────────────┤\n│ Operation │ QPS │ Avg(μs) │ P50(μs) │ P99(μs) │ Bytes/s │\n├────────────┼───────┼──────────┼──────────┼──────────┼────────────────┤\n│ GET │ 112 │ 1671.8 │ 12.3 │ 25165.8 │ 12.0 KB/s │\n│ PUT │ 11 │ 6.3 │ 6.1 │ 24.6 │ 1.5 KB/s │\n│ WRITE │ 0 │ 58.7 │ 49.2 │ 49.2 │ — │\n│ ITER_NEW │ 0 │ 21.5 │ 24.6 │ 24.6 │ — │\n│ TXN_COMMIT │ 0 │ 177592.5 │ 50331.6 │402653.2 │ 1.5 KB/s │\n╰────────────┴───────┴──────────┴──────────┴──────────┴────────────────╯\nStatus: ⏳ Warming up — Collecting baseline (285s remaining).\nDemo 3: demo-histogram（延迟分布直方图）\n命令：\ndocker run --rm --privileged --pid host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /root/ckb-testnet:/data \\\n-v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\nckb-probe:latest demo-histogram 60\n实际输出：\nGET latency distribution:\n2μs │████ 6\n4μs │████████████████████████████████████████ 404\n8μs │███████████████ 150\n16μs │██████████████████████ 212\n32μs │████████████ 60\n65μs │█ 2\n131μs │█ 3\nGET latency distribution (next cycle):\n2μs │█ 5\n4μs │████████████████████████████████████████ 215\n8μs │█████████████ 72\n16μs │████████████ 68\n32μs │████████ 42\n65μs │█ 3\n131μs │ 2\nDemo 4: demo-slow（慢操作捕获）\n命令：\ndocker run --rm --privileged --pid host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /root/ckb-testnet:/data \\\n-v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\nckb-probe:latest demo-slow 60 1000\n参数说明：60 = 运行 60 秒，1000 = 阈值 1000us\n实际输出：\n╭───────────────── Slow Operations (threshold: 1000μs) ──────────────────╮\n│ Timestamp │ Op │ Latency │ Size │ Note │\n├───────────────┼────────────┼───────────┼──────────┼────────────────────┤\n│ 18:25.870 │ GET │ 3,060μs │ 32 B │ │\n│ 18:25.892 │ GET │ 22,348μs │ 240 B │ │\n│ 18:25.928 │ GET │ 36,416μs │ 125 B │ │\n│ 18:25.953 │ GET │ 24,177μs │ 8 B │ │\n│ 18:25.956 │ GET │ 3,211μs │ 32 B │ │\n│ 18:26.006 │ GET │ 50,378μs │ 240 B │ │\n│ 18:26.042 │ GET │ 36,064μs │ 101 B │ │\n│ 18:26.068 │ GET │ 25,758μs │ 8 B │ │\n╰───────────────┴────────────┴───────────┴──────────┴────────────────────╯\nShowing 8 of 157 slow operations in last 15s.\nBPF event loss: 0 / 157 attempted (0.0000%)\nDemo 5: demo-normal（JSON 监控输出）\n命令：\ndocker run --rm --privileged --pid host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /root/ckb-testnet:/data \\\n-v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n-v /tmp/output:/tmp/perf-run \\\nckb-probe:latest demo-normal 60\n实际输出（最后一个采样周期）：\n{\n\"anomalies\": [],\n\"operations\": {\n\"GET\": {\n\"avg_us\": 421.02,\n\"bytes_per_sec\": 5629,\n\"p50_us\": 12.29,\n\"p99_us\": 12582.91,\n\"qps\": 50\n},\n\"ITER_NEW\": {\n\"avg_us\": 33.57,\n\"bytes_per_sec\": null,\n\"p50_us\": 24.58,\n\"p99_us\": 49.15,\n\"qps\": 3\n},\n\"PUT\": {\n\"avg_us\": 5.82,\n\"bytes_per_sec\": 1676,\n\"p50_us\": 6.14,\n\"p99_us\": 24.58,\n\"qps\": 13\n},\n\"TXN_COMMIT\": {\n\"avg_us\": 54568.75,\n\"bytes_per_sec\": 1676,\n\"p50_us\": 786.43,\n\"p99_us\": 201326.59,\n\"qps\": 0\n},\n\"WRITE\": {\n\"avg_us\": 51.8,\n\"bytes_per_sec\": null,\n\"p50_us\": 49.15,\n\"p99_us\": 49.15,\n\"qps\": 0\n}\n},\n\"pid\": 2349824,\n\"timestamp\": \"2026-05-02T07:52:39Z\",\n\"uptime_secs\": 15\n}\n输出保存到 /tmp/perf-run/demo/demo-normal-snapshot.json。\nDemo 6: demo-stress（压力注入 + 异常检测）\n命令：\ndocker run --rm --privileged --pid host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /root/ckb-testnet:/data \\\n-v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n-v /tmp/output:/tmp/perf-run \\\nckb-probe:latest demo-stress 50000\n参数说明：50000 = db_bench 写入 50,000 条记录（每条 4KB，共 ~195MB）\n实际输出：\n════════════════════════════════════════════════════════════════\ndemo-stress — synthetic RocksDB load injection (db_bench)\n════════════════════════════════════════════════════════════════\nckb pid : 2349824\ndb_bench size : 50000 entries × 4KB = ~195 MB\noutput : /tmp/perf-run/demo/demo-stress.txt\n[demo-stress] starting ckb-probe rocksdb --slow --threshold 500\n[demo-stress] ckb-probe pid=3548386\n[demo-stress] capturing 15s baseline...\n[demo-stress] launching db_bench fillrandom --num=50000 --threads=4\n[demo-stress] waiting for db_bench to complete...\n[demo-stress] db_bench done\n[demo-stress] 30s cool-down...\n════════════════════════════════════════════════════════════════\ndemo-stress result\n2026-05-02 07:54:08\n════════════════════════════════════════════════════════════════\nckb-probe captured during stress:\nANOMALY DETECTED count : 0\nslow op log lines : 128\nBPF event loss: 0 / 215 attempted (0.0000%)\nNote: no ANOMALY DETECTED triggered. This can happen if the disk had\nenough headroom to absorb db_bench without contending with CKB.\nTry with a larger --num or apply db-options.aggressive via case-2.\n注：本次测试磁盘有足够的 I/O headroom 吸收了 db_bench 负载，未触发 ANOMALY DETECTED。在磁盘 I/O 更紧张的环境下（或使用 aggressive RocksDB 调优），异常检测会被触发。Case 2 的压缩风暴测试已验证此能力（GET 延迟 35x 飙升，6,112 个慢操作）。\nD.4 三项长时间测试的 Docker 命令\n48h 稳定性测试 (S-1 ~ S-4)\ndocker run -d --name stability-test \\\n--privileged --pid host --network host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /root/ckb-testnet:/data \\\n-v /root/ckb-testnet/ckb:/root/ckb-testnet/ckb:ro \\\n-v /tmp/perf-run:/tmp/perf-run \\\n-e CKB_BIN=/root/ckb-testnet/ckb \\\n-e CKB_RPC=http://127.0.0.1:8124 \\\nckb-probe:latest stability\n# 查看进度\ndocker logs -f stability-test\n# 测试完成后生成报告\ndocker exec stability-test bash -c \\\n'/opt/scripts/stability/generate-report.sh /path/to/stability-<timestamp>/'\n测试内容：48 小时持续运行，3 个 ckb-probe 实例并行采集，含 T+24h 的 CKB 进程重启恢复测试。\nCase 1: IBD 写入模式 (最长 2 小时)\ndocker run --rm \\\n--privileged --pid host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /root/ckb-testnet:/data \\\n-v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n-v /tmp/case-output:/tmp/perf-run \\\n--entrypoint bash \\\nckb-probe:latest -c '\n/opt/scripts/case/start-ckb.sh\n/opt/scripts/case/case-1-ibd-write-pattern.sh 7200\n'\n脚本会自动在 tip 追上网络最新高度时提前退出。\nCase 2: 压缩风暴捕获 (最长 30 分钟)\ndocker run --rm \\\n--privileged --pid host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /root/ckb-testnet:/data \\\n-v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n-v /tmp/case-output:/tmp/perf-run \\\n--entrypoint bash \\\nckb-probe:latest -c '\n/opt/scripts/case/start-ckb.sh\n/opt/scripts/case/case-2-compaction-storm.sh 1800\n'\n脚本会自动应用 aggressive RocksDB 调优、重启 CKB、挂载探针、等待慢操作数据，结束后自动恢复原始配置。\nP-1 ~ P-4 性能测试 (约 4 小时)\ndocker run --rm \\\n--privileged --pid host \\\n-v /sys/kernel/debug:/sys/kernel/debug:ro \\\n-v /sys/kernel/btf:/sys/kernel/btf:ro \\\n-v /root/ckb-testnet:/data \\\n-v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n-v /tmp/perf-output:/tmp/perf-run \\\nckb-probe:latest perf\nPhase A (2h with-probe) + Phase B (2h baseline)，均从相同 tip 启动，自动对比 CPU / RSS / 事件丢失 / 同步速度。",
          "content_html": "<h1><a name=\"p-24112-ckb-probe-1\" class=\"anchor\" href=\"#p-24112-ckb-probe-1\" aria-label=\"Heading link\"></a>CKB-Probe 演示流程说明</h1>\n<blockquote>\n<p><strong>范围：仅限 CKB 测试网</strong></p>\n<p>本文档覆盖 ckb-probe 的五个核心演示步骤，每步附完整终端输出、关键命令说明和输出解读。<br>\n所有输出均为真实运行数据（2026-05-02，CKB v0.204.0 测试网节点）。</p>\n</blockquote>\n<hr>\n<h2><a name=\"p-24112-h-2\" class=\"anchor\" href=\"#p-24112-h-2\" aria-label=\"Heading link\"></a>调整说明</h2>\n<p>本文档替代原计划的演示视频。文字报告在以下方面对评审者更为友好：</p>\n<ul>\n<li>评审者可以直接复制报告中的命令进行复现，不需要反复拖动视频进度条</li>\n<li>终端输出配合文字解读比视频旁白更容易精确定位到具体的输出字段和数值</li>\n<li>报告本身可以作为项目文档的一部分长期保留，便于后续版本更新时同步修改</li>\n<li>视频一旦录制后修改成本较高，而文档可以随项目迭代</li>\n</ul>\n<hr>\n<h2><a name=\"p-24112-h-3\" class=\"anchor\" href=\"#p-24112-h-3\" aria-label=\"Heading link\"></a>前置条件</h2>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\"># 系统要求\n# - Linux 内核 &gt;= 5.8 (BTF 支持)\n# - root 权限 (eBPF 需要 CAP_BPF + CAP_SYS_ADMIN)\n# - CKB 测试网节点运行中\n\n# Docker 方式运行 (推荐)\ndocker run --rm --privileged --pid host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /path/to/ckb-testnet:/data \\\n  -v /path/to/ckb:/usr/local/bin/ckb:ro \\\n  ckb-probe:latest &lt;command&gt;\n\n# 或者直接在宿主机运行 (需要 root)\nsudo ckb-probe &lt;command&gt;\n</code></pre>\n<hr>\n<h2><a name=\"p-24112-h-1-ebpf-4\" class=\"anchor\" href=\"#p-24112-h-1-ebpf-4\" aria-label=\"Heading link\"></a>步骤 1: 环境检查与 eBPF 验证</h2>\n<p><strong>目的：</strong> 验证 eBPF 环境就绪、CKB 二进制可探测、所有 uprobe/kprobe/tracepoint 可挂载。</p>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">sudo ckb-probe check --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb)\n</code></pre>\n<p><strong>完整终端输出：</strong></p>\n<pre><code class=\"lang-auto\">╔══════════════════════════════════════════════════════════════╗\n║  ckb-probe environment check                               ║\n╠══════════════════════════════════════════════════════════════╣\n  ✅ Kernel version            6.8.0-106-generic (need &gt;= 5.8)\n  ✅ BPF config                BPF=y SYSCALL=y JIT=y\n  ✅ BTF support               /sys/kernel/btf/vmlinux exists\n  ✅ Permissions               running as root\n  ✅ bpf() syscall             available\n  ✅ uprobe support            /sys/kernel/debug/tracing/uprobe_events exists\n  ✅ CKB process               1 instance(s), pid=2349824\n  ✅ CKB symbols               2/3 key symbols found (symtab)\n╚══════════════════════════════════════════════════════════════╝\n\n  Result: 8/8 checks passed\n  🎉 All checks passed!\n\n\n╔═════���════════════════════════════════════════════════════════╗\n║  ckb-probe eBPF validation                                 ║\n╠══════════════════════════════════════════════════════════════╣\n  ✅ ── uprobe latency ──      entry/return pair attach test\n  ✅   rocksdb_get_pinned_cf   entry + return attached\n  ✅   rocksdb_put             entry + return attached\n  ✅   rocksdb_write           entry + return attached\n  ❌   rocksdb_delete          symbol not in binary (expected)\n  ✅   rocksdb_create_iterator_cf  entry + return attached\n  ❌   rocksdb_multi_get_cf    symbol not in binary (expected)\n  ✅ ── uprobe Tier 1 ──       all 19 Tier 1 symbol attach test\n  ✅   rocksdb_get             symbol found, uprobe-attachable\n  ✅   rocksdb_get_pinned      symbol found, uprobe-attachable\n  ✅   rocksdb_get_pinned_cf   symbol found, uprobe-attachable\n  ✅   rocksdb_put             symbol found, uprobe-attachable\n  ✅   rocksdb_put_cf          symbol found, uprobe-attachable\n  ✅   rocksdb_write           symbol found, uprobe-attachable\n  ❌   rocksdb_delete          not found in binary\n  ❌   rocksdb_delete_cf       not found in binary\n  ❌   rocksdb_multi_get_cf    not found in binary\n  ✅   rocksdb_transaction_put_cf  symbol found, uprobe-attachable\n  ✅   rocksdb_transaction_delete_cf  symbol found, uprobe-attachable\n  ❌   rocksdb_transaction_get_cf  not found in binary\n  ✅   rocksdb_transaction_commit  symbol found, uprobe-attachable\n  ✅   rocksdb_optimistictransaction_begin  symbol found, uprobe-attachable\n  ✅   rocksdb_create_iterator_cf  symbol found, uprobe-attachable\n  ✅   rocksdb_iter_seek       symbol found, uprobe-attachable\n  ✅   rocksdb_iter_seek_to_first  symbol found, uprobe-attachable\n  ✅   rocksdb_iter_next       symbol found, uprobe-attachable\n  ✅   rocksdb_iter_destroy    symbol found, uprobe-attachable\n  ✅ uprobe summary            latency pairs: 4/6, Tier 1 symbols: 15/19\n  ✅ kprobe tcp_sendmsg_entry  attached to tcp_sendmsg\n  ✅ kprobe tcp_sendmsg_return attached to tcp_sendmsg\n  ✅ kprobe tcp_recvmsg_entry  attached to tcp_recvmsg\n  ✅ kprobe tcp_recvmsg_return attached to tcp_recvmsg\n  ✅ tracepoint sys_enter      attached to raw_syscalls/sys_enter\n╚══════════════════════════════════════════════════════════════╝\n\n  Result: 27/33 checks passed\n\n  ⏳ Collecting live events for 3 seconds...\n\n  [syscall] pid=2349824 tid=808096 nr=232 (epoll_wait)\n  [uprobe] pid=2349824 tid=2351140 func=get_pinned_cf            latency=45.2μs\n  [uprobe] pid=2349824 tid=2351140 func=get_pinned_cf            latency=14.5μs\n  [uprobe] pid=2349824 tid=2351140 func=get_pinned_cf            latency=5.3μs\n  [uprobe] pid=2349824 tid=2351140 func=get_pinned_cf            latency=6.0μs\n  [uprobe] pid=2349824 tid=2351140 func=get_pinned_cf            latency=4.5μs\n  [tcp] pid=2349824 tid=740351 dir=RX bytes=705\n  [tcp] pid=2349824 tid=808096 dir=TX bytes=705\n\n  📊 Captured 264 uprobe, 40 tcp, 438 syscall events in 3s\n</code></pre>\n<p><strong>解读：</strong></p>\n<ul>\n<li><strong>环境检查 8/8 全部通过</strong>：内核 6.8.0 满足 &gt;= 5.8 要求，BTF 可用，root 权限，bpf() 系统调用可用</li>\n<li><strong>eBPF 验证 27/33 通过</strong>：4 个 uprobe 延迟对（GET/PUT/WRITE/ITER）成功挂载，15/19 个 Tier 1 符号可用，4 个未找到的符号（delete/multi_get/transaction_get_cf）是 CKB 未使用的 RocksDB API，属于预期缺失</li>\n<li><strong>kprobe/tracepoint 全部成功</strong>：tcp_sendmsg/tcp_recvmsg 网络探针 + raw_syscalls 系统调用追踪</li>\n<li><strong>实时事件采集验证</strong>：3 秒内捕获 264 个 uprobe 事件 + 40 个 TCP 事件 + 438 个 syscall 事件，证明数据通道正常</li>\n</ul>\n<hr>\n<h2><a name=\"p-24112-h-2-5\" class=\"anchor\" href=\"#p-24112-h-2-5\" aria-label=\"Heading link\"></a>步骤 2: 符号分析</h2>\n<p><strong>目的：</strong> 全面分析 CKB 二进制中的 RocksDB 符号，评估 uprobe 覆盖率。</p>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">ckb-probe symbols /root/ckb-testnet/ckb\n</code></pre>\n<p><strong>完整终端输出：</strong></p>\n<pre><code class=\"lang-auto\">════════════════════════════════════════════════════════════════════\n   CKB Binary Symbol Analysis Report\n   Binary: /root/ckb-testnet/ckb (65.0 MB)\n   Format: ELF 64-bit x86_64\n════════════════════════════════════════════════════════════════════\n\n── ELF Overview ────────────────────────────────────────\n  .symtab:        ✅ Present (153057 symbols)\n  .dynsym:        ✅ Present (511 symbols)\n  DWARF:          ❌ Not found\n  Strip status:   debuginfo-stripped (.symtab retained)\n\n── RocksDB Linkage ─────────────────────────────────────\n  Method:         Static (bundled into CKB binary)\n  Evidence:       No librocksdb.so in dynamic deps; 155 rocksdb_* in .symtab\n  Assessment:     ✅ Ideal — C API symbols embedded in binary\n\n── Dynamic Dependencies ────────────────────────────────\n  libstdc++.so.6            libgcc_s.so.1             libm.so.6\n  libc.so.6                 ld-linux-x86-64.so.2\n\n── [Tier 1] Directly uprobe-attachable (extern \"C\", stable) ──\n  ✅ rocksdb_get                                    0x021e3330  (318 B)\n  ✅ rocksdb_get_cf                                 0x021e34a0  (215 B)\n  ✅ rocksdb_get_pinned                             0x021e4b20  (427 B)\n  ✅ rocksdb_get_pinned_cf                          0x021e4d00  (379 B)\n  ✅ rocksdb_put                                    0x021e30a0  (105 B)\n  ✅ rocksdb_put_cf                                 0x021e3120  (240 B)\n  ✅ rocksdb_write                                  0x021e3230  (208 B)\n  ✅ rocksdb_transaction_put_cf                     0x021e4770  (113 B)\n  ✅ rocksdb_transaction_delete_cf                  0x021e4800  (101 B)\n  ✅ rocksdb_transaction_commit                     0x021e42f0  (71 B)\n  ✅ rocksdb_optimistictransaction_begin            0x021e4a50  (99 B)\n  ✅ rocksdb_create_iterator_cf                     0x021e3670  (167 B)\n  ✅ rocksdb_iter_seek                              0x021e3b30  (30 B)\n  ✅ rocksdb_iter_seek_to_first                     0x021e3b10  (9 B)\n  ✅ rocksdb_iter_next                              0x021e3b70  (9 B)\n  ✅ rocksdb_iter_destroy                           0x021e3ae0  (32 B)\n  → 16 / 20 tracked targets found\n\n── [Tier 2] Possibly available (Rust mangled, version-bound) ──\n  ⚠️  ckb_network::network::NetworkService::start\n  ⚠️  ckb_sync::synchronizer::block_process::BlockProcess::execute\n  ⚠️  ckb_sync::synchronizer::headers_process::HeadersProcess::execute\n  ⚠️  ckb_chain::chain_controller::ChainController::asynchronous_process_remote_block\n  ⚠️  ckb_store::transaction::StoreTransaction::attach_block\n  ⚠️  ckb_store::transaction::StoreTransaction::insert_block\n  ⚠️  ckb_store::transaction::StoreTransaction::commit\n  ⚠️  ckb_db::db::RocksDB::get_pinned\n  ⚠️  ckb_db::db::RocksDB::get_pinned_default\n  ... (11 / 21 tracked targets found)\n\n── [Tier 3] Unavailable (inlined / stripped / crate-internal) ──\n  ❌ ckb_network::protocols::CKBHandler::received — not found (likely inlined)\n  ❌ ckb_chain::chain_service::ChainService::process_block — not found (likely inlined)\n  ❌ ckb_store::db::ChainDB::get_block — not found (likely inlined)\n  ... (19 tracked functions not found)\n\n── Summary ─────────────────────────────────────────────\n  Tier 1:  16 / 20  ( 80%)  partial coverage ⚠️\n  Tier 2:  11 / 21  ( 52%)  available in this binary\n  Tier 3:  19 tracked functions not found\n  Total function symbols:      86852\n  Total RocksDB C API symbols: 155\n════════════════════════════════════════════════════════════════════\n</code></pre>\n<p><strong>解读：</strong></p>\n<ul>\n<li><strong>Tier 1 (C API)</strong> — 16/20 找到（80%），这些是 <code>extern \"C\"</code> 符号，跨 CKB 版本稳定，是 ckb-probe 的核心探测点</li>\n<li><strong>RocksDB 静态链接</strong> — 155 个 <code>rocksdb_*</code> 符号直接嵌入 CKB 二进制，无需额外的 <code>.so</code> 文件</li>\n<li><strong>Tier 2 (Rust mangled)</strong> — 11/21 找到，这些 Rust 函数名含编译哈希，不同版本可能变化</li>\n<li><strong>Tier 3 (inlined)</strong> — 19 个预期缺失，因为编译器内联优化消除了这些函数入口</li>\n</ul>\n<hr>\n<h2><a name=\"p-24112-h-3-rocksdb-6\" class=\"anchor\" href=\"#p-24112-h-3-rocksdb-6\" aria-label=\"Heading link\"></a>步骤 3: 正常同步期间的实时 RocksDB 监控</h2>\n<p><strong>目的：</strong> 在 CKB 测试网节点正常运行期间，实时展示五类 RocksDB 操作的延迟、吞吐和延迟分布。</p>\n<h3><a name=\"p-24112-h-3a-7\" class=\"anchor\" href=\"#p-24112-h-3a-7\" aria-label=\"Heading link\"></a>3a. 统计表格模式</h3>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">sudo ckb-probe rocksdb --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb) --interval 5\n</code></pre>\n<p><strong>终端输出：</strong></p>\n<pre><code class=\"lang-auto\">╭───────────────── CKB RocksDB Monitor (PID: 2349824) ─────────────────╮\n│ Uptime: 00:00:05   Sampling: 5s   Node: CKB v0.204.0               │\n├────────────┬───────┬──────────┬──────────┬──────────┬────────────────┤\n│ Operation  │  QPS  │ Avg(μs)  │ P50(μs)  │ P99(μs)  │    Bytes/s    │\n├────────────┼───────┼──────────┼──────────┼──────────┼────────────────┤\n│ GET        │    93 │    23.8  │     6.1  │   196.6  │   5.5 KB/s    │\n│ PUT        │     8 │     6.7  │     6.1  │    24.6  │    624 B/s    │\n│ WRITE      │     0 │    43.1  │    49.2  │    49.2  │       —       │\n│ ITER_NEW   │     1 │    38.6  │    49.2  │    98.3  │       —       │\n│ TXN_COMMIT │     1 │   326.7  │   393.2  │   393.2  │    624 B/s    │\n╰────────────┴───────┴──────────┴──────────┴──────────┴────────────────╯\n  Status: ⏳ Warming up — Collecting baseline (295s remaining).\n</code></pre>\n<pre><code class=\"lang-auto\">╭───────────────── CKB RocksDB Monitor (PID: 2349824) ─────────────────╮\n│ Uptime: 00:00:10   Sampling: 5s   Node: CKB v0.204.0               │\n├────────────┬───────┬──────────┬──────────┬──────────┬────────────────┤\n│ Operation  │  QPS  │ Avg(μs)  │ P50(μs)  │ P99(μs)  │    Bytes/s    │\n├────────────┼───────┼──────────┼──────────┼──────────┼────────────────┤\n│ GET        │   177 │   411.6  │    12.3  │ 12582.9  │  21.5 KB/s    │\n│ PUT        │     0 │     0.0  │     0.0  │     0.0  │     0 B/s     │\n│ WRITE      │     0 │     0.0  │     0.0  │     0.0  │       —       │\n│ ITER_NEW   │     0 │     0.0  │     0.0  │     0.0  │       —       │\n│ TXN_COMMIT │     0 │     0.0  │     0.0  │     0.0  │     0 B/s     │\n╰────────────┴───────┴──────────┴──────────┴──────────┴────────────────╯\n  Status: ⏳ Warming up — Collecting baseline (290s remaining).\n</code></pre>\n<h3><a name=\"p-24112-h-3b-8\" class=\"anchor\" href=\"#p-24112-h-3b-8\" aria-label=\"Heading link\"></a>3b. 延迟分布直方图模式</h3>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">sudo ckb-probe rocksdb --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb) --histogram --interval 5\n</code></pre>\n<p><strong>终端输出（表格下方附加直方图）：</strong></p>\n<pre><code class=\"lang-auto\">  GET latency distribution:\n         2μs │████                                        22\n         4μs │████████████████████████████████████████   369\n         8μs │███████████████████                        182\n        16μs │██████████████████                         213\n        32μs │██████████                                  46\n        65μs │██                                           6\n\n  PUT latency distribution:\n         2μs │██████                                       3\n         4μs │████████████████████████████████████████    10\n         8μs │████                                         2\n        16μs │██████                                       3\n        32μs │██                                           1\n\n  WRITE latency distribution:\n        32μs │████████████████████████████████████████     1\n\n  ITER_NEW latency distribution:\n        16μs │████████████████████████████████████████     2\n        32μs │████████████████████████████████████████     2\n\n  TXN_COMMIT latency distribution:\n        65μs │████████████████████                         1\n       262μs │████████████████████████████████████████     2\n</code></pre>\n<p><strong>解读：</strong></p>\n<ul>\n<li><strong>GET</strong> 呈长尾分布：主体在 2~32us（缓存命中），少量尾部延迟由磁盘 I/O 引起</li>\n<li><strong>PUT</strong> 集中在 4~16us，单次写入非常轻量</li>\n<li><strong>TXN_COMMIT</strong> 在 65~262us 区间，反映 WAL 写入开销</li>\n<li>直方图数据来自 eBPF 内核态 per-CPU 计数器，零采样开销</li>\n</ul>\n<hr>\n<h2><a name=\"p-24112-h-4-9\" class=\"anchor\" href=\"#p-24112-h-4-9\" aria-label=\"Heading link\"></a>步骤 4: 慢操作捕获</h2>\n<p><strong>目的：</strong> 实时捕获超过阈值的 RocksDB 操作，展示每个慢操作的精确延迟、数据大小和 BPF 事件丢失率。</p>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">sudo ckb-probe rocksdb --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb) \\\n  --slow --threshold 1000 --interval 5\n</code></pre>\n<p><strong>终端输出：</strong></p>\n<pre><code class=\"lang-auto\">╭───────────────── Slow Operations (threshold: 1000μs) ──────────────────╮\n│ Timestamp     │ Op         │   Latency │     Size │ Note               │\n├───────────────┼────────────┼───────────┼──────────┼────────────────────┤\n│ 57:21.976     │ GET        │   8,162μs │    125 B │                    │\n│ 57:21.986     │ GET        │   9,389μs │    240 B │                    │\n│ 57:21.992     │ GET        │   5,346μs │    125 B │                    │\n│ 57:21.998     │ GET        │   6,167μs │      8 B │                    │\n│ 57:22.004     │ GET        │   5,484μs │    173 B │                    │\n│ 57:22.007     │ GET        │   3,084μs │      8 B │                    │\n╰───────────────┴────────────┴───────────┴──────────┴────────────────────╯\n  Showing 8 of 13 slow operations in last 5s.\n  BPF event loss: 0 / 13 attempted  (0.0000%)\n</code></pre>\n<pre><code class=\"lang-auto\">╭───────────────── Slow Operations (threshold: 1000μs) ──────────────────╮\n│ Timestamp     │ Op         │   Latency │     Size │ Note               │\n├───────────────┼────────────┼───────────┼──────────┼────────────────────┤\n│ 57:29.099     │ GET        │   7,207μs │      8 B │                    │\n│ 57:29.104     │ GET        │   5,223μs │     32 B │                    │\n│ 57:29.107     │ GET        │   2,432μs │    240 B │                    │\n│ 57:29.115     │ GET        │   8,238μs │    101 B │                    │\n│ 57:29.127     │ GET        │  11,631μs │     32 B │                    │\n│ 57:29.130     │ GET        │   3,230μs │    240 B │                    │\n│ 57:29.134     │ GET        │   4,002μs │    101 B │                    │\n│ 57:29.137     │ GET        │   2,946μs │      8 B │                    │\n╰───────────────┴────────────┴───────────┴──────────┴────────────────────╯\n  Showing 8 of 32 slow operations in last 10s.\n  BPF event loss: 0 / 32 attempted  (0.0000%)\n</code></pre>\n<p><strong>解读：</strong></p>\n<ul>\n<li>仅超过 1000us (1ms) 的操作被捕获，常态下对系统零开销</li>\n<li>慢操作全部为 GET，延迟在 2~11ms，由 RocksDB block cache miss 触发磁盘读取导致</li>\n<li><strong>BPF event loss: 0 / 32 (0.0000%)</strong> — RingBuf 数据通道零丢失</li>\n<li>Size 列显示该操作读写的数据大小（8B = key, 32~240B = value）</li>\n</ul>\n<hr>\n<h2><a name=\"p-24112-h-5-json-10\" class=\"anchor\" href=\"#p-24112-h-5-json-10\" aria-label=\"Heading link\"></a>步骤 5: JSON 导出</h2>\n<p><strong>目的：</strong> 展示机器可读的 JSON 输出格式，适合下游监控管线和数据分析。</p>\n<h3><a name=\"p-24112-h-5a-json-11\" class=\"anchor\" href=\"#p-24112-h-5a-json-11\" aria-label=\"Heading link\"></a>5a. 标准 JSON 输出</h3>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">sudo ckb-probe rocksdb --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb) \\\n  --json --interval 5\n</code></pre>\n<p><strong>终端输出（单个采样周期）：</strong></p>\n<pre data-code-wrap=\"json\"><code class=\"lang-json\">{\n  \"anomalies\": [],\n  \"operations\": {\n    \"GET\": {\n      \"avg_us\": 19.71,\n      \"bytes_per_sec\": 1673,\n      \"p50_us\": 12.29,\n      \"p99_us\": 98.3,\n      \"qps\": 22\n    },\n    \"ITER_NEW\": {\n      \"avg_us\": 0.0,\n      \"bytes_per_sec\": null,\n      \"p50_us\": 0.0,\n      \"p99_us\": 0.0,\n      \"qps\": 0\n    },\n    \"PUT\": {\n      \"avg_us\": 0.0,\n      \"bytes_per_sec\": 0,\n      \"p50_us\": 0.0,\n      \"p99_us\": 0.0,\n      \"qps\": 0\n    },\n    \"TXN_COMMIT\": {\n      \"avg_us\": 0.0,\n      \"bytes_per_sec\": 0,\n      \"p50_us\": 0.0,\n      \"p99_us\": 0.0,\n      \"qps\": 0\n    },\n    \"WRITE\": {\n      \"avg_us\": 0.0,\n      \"bytes_per_sec\": null,\n      \"p50_us\": 0.0,\n      \"p99_us\": 0.0,\n      \"qps\": 0\n    }\n  },\n  \"pid\": 2349824,\n  \"timestamp\": \"2026-05-02T07:31:41Z\",\n  \"uptime_secs\": 0\n}\n</code></pre>\n<h3><a name=\"p-24112-h-5b-json-12\" class=\"anchor\" href=\"#p-24112-h-5b-json-12\" aria-label=\"Heading link\"></a>5b. JSON + 直方图融合输出</h3>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">sudo ckb-probe rocksdb --binary /root/ckb-testnet/ckb --pid $(pgrep -x ckb) \\\n  --json --histogram --interval 5\n</code></pre>\n<p><strong>终端输出（单个采样周期，含 histogram 字段）：</strong></p>\n<pre data-code-wrap=\"json\"><code class=\"lang-json\">{\n  \"anomalies\": [],\n  \"operations\": {\n    \"GET\": {\n      \"avg_us\": 244.69,\n      \"bytes_per_sec\": 11803,\n      \"histogram\": [\n        { \"count\": 25, \"ge_us\": 4.1 },\n        { \"count\": 5, \"ge_us\": 8.19 },\n        { \"count\": 6, \"ge_us\": 16.38 }\n      ],\n      \"p50_us\": 12.29,\n      \"p99_us\": 12582.91,\n      \"qps\": 116\n    },\n    \"PUT\": {\n      \"avg_us\": 6.26,\n      \"bytes_per_sec\": 1439,\n      \"histogram\": [\n        { \"count\": 10, \"ge_us\": 4.1 },\n        { \"count\": 2, \"ge_us\": 8.19 },\n        { \"count\": 3, \"ge_us\": 16.38 }\n      ],\n      \"p50_us\": 6.14,\n      \"p99_us\": 49.15,\n      \"qps\": 10\n    }\n  },\n  \"pid\": 2349824,\n  \"timestamp\": \"2026-05-02T07:32:11Z\",\n  \"uptime_secs\": 5\n}\n</code></pre>\n<h3><a name=\"p-24112-h-5c-json-13\" class=\"anchor\" href=\"#p-24112-h-5c-json-13\" aria-label=\"Heading link\"></a>5c. JSON 字段说明</h3>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>字段</th>\n<th>类型</th>\n<th>说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>timestamp</code></td>\n<td>string</td>\n<td>ISO 8601 UTC 时间戳</td>\n</tr>\n<tr>\n<td><code>pid</code></td>\n<td>number</td>\n<td>目标 CKB 进程 PID</td>\n</tr>\n<tr>\n<td><code>uptime_secs</code></td>\n<td>number</td>\n<td>ckb-probe 运行时长（秒）</td>\n</tr>\n<tr>\n<td><code>operations</code></td>\n<td>object</td>\n<td>五个 RocksDB 操作的实时指标</td>\n</tr>\n<tr>\n<td><code>operations.*.qps</code></td>\n<td>number</td>\n<td>每秒操作数</td>\n</tr>\n<tr>\n<td><code>operations.*.avg_us</code></td>\n<td>number</td>\n<td>平均延迟（微秒）</td>\n</tr>\n<tr>\n<td><code>operations.*.p50_us</code></td>\n<td>number</td>\n<td>P50 延迟（微秒，log2 直方图插值）</td>\n</tr>\n<tr>\n<td><code>operations.*.p99_us</code></td>\n<td>number</td>\n<td>P99 延迟（微秒，log2 直方图插值）</td>\n</tr>\n<tr>\n<td><code>operations.*.bytes_per_sec</code></td>\n<td>number / null</td>\n<td>吞吐量（B/s），WRITE/ITER_NEW 为 null</td>\n</tr>\n<tr>\n<td><code>operations.*.histogram</code></td>\n<td>array</td>\n<td>log2 延迟分布（仅 <code>--histogram</code> 时出现）</td>\n</tr>\n<tr>\n<td><code>operations.*.histogram[].ge_us</code></td>\n<td>number</td>\n<td>桶下界（微秒）</td>\n</tr>\n<tr>\n<td><code>operations.*.histogram[].count</code></td>\n<td>number</td>\n<td>该桶内的操作数</td>\n</tr>\n<tr>\n<td><code>anomalies</code></td>\n<td>array</td>\n<td>EWMA 异常事件（5 分钟 warmup 后启用）</td>\n</tr>\n<tr>\n<td><code>anomalies.*.trigger</code></td>\n<td>string</td>\n<td>触发条件组合：AVG / P99 / CAP</td>\n</tr>\n<tr>\n<td><code>anomalies.*.multiplier</code></td>\n<td>number</td>\n<td>当前均值 / 基线均值</td>\n</tr>\n</tbody>\n</table>\n</div><hr>\n<h2><a name=\"p-24112-a-48h-14\" class=\"anchor\" href=\"#p-24112-a-48h-14\" aria-label=\"Heading link\"></a>附录 A: 48h 稳定性测试结果摘要</h2>\n<blockquote>\n<p>完整报告见 <code>docs/STABILITY-REPORT_zh.md</code></p>\n</blockquote>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>#</th>\n<th>指标</th>\n<th>结果</th>\n<th>关键数据</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>S-1</td>\n<td>无崩溃</td>\n<td><strong>PASS</strong></td>\n<td>48h 全程无 panic/SIGSEGV</td>\n</tr>\n<tr>\n<td>S-2</td>\n<td>内存稳定</td>\n<td><strong>PASS</strong></td>\n<td>RSS 增长 0.00 MB（预算 5 MB）</td>\n</tr>\n<tr>\n<td>S-3</td>\n<td>无 BPF 错误</td>\n<td><strong>PASS</strong>*</td>\n<td>误报（systemd 版本字符串匹配）</td>\n</tr>\n<tr>\n<td>S-4</td>\n<td>重启恢复</td>\n<td><strong>PASS</strong></td>\n<td>CKB 重启后 1 秒重连</td>\n</tr>\n</tbody>\n</table>\n</div><p>资源使用：Probe CPU P99=0.29%，RSS 稳定 21.4 MB，BPF 事件丢失 0/126,934 (0.0000%)</p>\n<h2><a name=\"p-24112-b-case-study-15\" class=\"anchor\" href=\"#p-24112-b-case-study-15\" aria-label=\"Heading link\"></a>附录 B: Case Study 结果摘要</h2>\n<blockquote>\n<p>完整报告见 <code>docs/CASE-STUDY-REPORT_zh.md</code></p>\n</blockquote>\n<p><strong>Case 1 (IBD 写入模式):</strong> 22 分钟完整 IBD 追赶，GET 主导 (109.7 QPS)，6 个 ITER_NEW 异常事件</p>\n<p><strong>Case 2 (压缩风暴):</strong> aggressive 调优下 GET 延迟从 ~200us 飙升至 6,988us (35x)，30 分钟捕获 6,112 个慢操作，零事件丢失</p>\n<h2><a name=\"p-24112-c-p-1p-4-16\" class=\"anchor\" href=\"#p-24112-c-p-1p-4-16\" aria-label=\"Heading link\"></a>附录 C: P-1~P-4 性能测试结果摘要</h2>\n<blockquote>\n<p>完整报告见 Week 5 周报</p>\n</blockquote>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>指标</th>\n<th>结果</th>\n<th>预算</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>P-1 CPU 开销</td>\n<td>+2.11% (2h 综合)</td>\n<td>&lt;= 3%</td>\n</tr>\n<tr>\n<td>P-2 RSS</td>\n<td>21.97 MB (稳定)</td>\n<td>&lt;= 50 MB</td>\n</tr>\n<tr>\n<td>P-3 事件丢失</td>\n<td>0/78,353 (0.0000%)</td>\n<td>&lt; 0.1%</td>\n</tr>\n<tr>\n<td>P-4 同步退化</td>\n<td>+0.37% (2h 综合)</td>\n<td>&lt; 1%</td>\n</tr>\n</tbody>\n</table>\n</div><p>四项全部 PASS。</p>\n<hr>\n<h2><a name=\"p-24112-h-17\" class=\"anchor\" href=\"#p-24112-h-17\" aria-label=\"Heading link\"></a>运行模式总结</h2>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>模式</th>\n<th>命令</th>\n<th>输出格式</th>\n<th>用途</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>环境检查</td>\n<td><code>check</code></td>\n<td>文本</td>\n<td>验证 eBPF 环境和符号可用性</td>\n</tr>\n<tr>\n<td>符号分析</td>\n<td><code>symbols</code></td>\n<td>文本 / JSON</td>\n<td>分析 CKB 二进制符号覆盖率</td>\n</tr>\n<tr>\n<td>实时表格</td>\n<td><code>rocksdb</code></td>\n<td>TUI 表格</td>\n<td>实时监控 QPS/延迟/吞吐</td>\n</tr>\n<tr>\n<td>延迟直方图</td>\n<td><code>rocksdb --histogram</code></td>\n<td>TUI 直方图</td>\n<td>分析延迟分布特征</td>\n</tr>\n<tr>\n<td>慢操作捕获</td>\n<td><code>rocksdb --slow</code></td>\n<td>TUI 列表</td>\n<td>捕获超阈值操作</td>\n</tr>\n<tr>\n<td>JSON 输出</td>\n<td><code>rocksdb --json</code></td>\n<td>JSONL</td>\n<td>机器可读，供下游管线消费</td>\n</tr>\n<tr>\n<td>JSON + 直方图</td>\n<td><code>rocksdb --json --histogram</code></td>\n<td>JSONL</td>\n<td>含 log2 延迟分布的完整导出</td>\n</tr>\n</tbody>\n</table>\n</div><hr>\n<h2><a name=\"p-24112-d-docker-18\" class=\"anchor\" href=\"#p-24112-d-docker-18\" aria-label=\"Heading link\"></a>附录 D: Docker 构建与运行指南</h2>\n<h3><a name=\"p-24112-d1-docker-19\" class=\"anchor\" href=\"#p-24112-d1-docker-19\" aria-label=\"Heading link\"></a>D.1 构建 Docker 镜像</h3>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">cd /root/ckb-probe\ndocker build -f docker/Dockerfile -t ckb-probe:latest .\n</code></pre>\n<p>构建过程：</p>\n<ul>\n<li><strong>Stage 1 (probe-builder)</strong>：安装 Rust nightly + clang/llvm + bpf-linker，编译 eBPF 内核程序 + 用户态 CLI + db_bench</li>\n<li><strong>Stage 2 (runtime)</strong>：Ubuntu 24.04 + 运行时工具，复制编译产物和脚本</li>\n<li>产物镜像约 123 MB</li>\n</ul>\n<h3><a name=\"p-24112-d2-docker-20\" class=\"anchor\" href=\"#p-24112-d2-docker-20\" aria-label=\"Heading link\"></a>D.2 通用 Docker 运行模板</h3>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\"># 基础命令模板（所有 demo / case / perf / stability 通用）\ndocker run --rm \\\n  --privileged --pid host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /path/to/ckb-testnet:/data \\\n  -v /path/to/ckb:/usr/local/bin/ckb:ro \\\n  -v /tmp/output:/tmp/perf-run \\\n  ckb-probe:latest &lt;command&gt; [args...]\n</code></pre>\n<p><strong>必需卷挂载说明：</strong></p>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>挂载</th>\n<th>用途</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>/sys/kernel/debug</code></td>\n<td>eBPF uprobe/kprobe 需要 debugfs</td>\n</tr>\n<tr>\n<td><code>/sys/kernel/btf</code></td>\n<td>BTF 类型信息（内核 &gt;= 5.8）</td>\n</tr>\n<tr>\n<td><code>/path/to/ckb-testnet:/data</code></td>\n<td>CKB 链数据目录</td>\n</tr>\n<tr>\n<td><code>/path/to/ckb:/usr/local/bin/ckb:ro</code></td>\n<td>CKB 二进制（路径需与宿主机进程 exe 匹配）</td>\n</tr>\n<tr>\n<td><code>/tmp/output:/tmp/perf-run</code></td>\n<td>输出目录（报告、日志）</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>必需权限：</strong></p>\n<ul>\n<li><code>--privileged</code>：eBPF 需要 CAP_BPF + CAP_SYS_ADMIN</li>\n<li><code>--pid host</code>：访问宿主机进程的 PID namespace</li>\n</ul>\n<hr>\n<h3><a name=\"p-24112-d3-docker-demo-21\" class=\"anchor\" href=\"#p-24112-d3-docker-demo-21\" aria-label=\"Heading link\"></a>D.3 Docker 内六个 Demo 执行方法与结果</h3>\n<p>以下所有命令均在 Docker 容器中执行，CKB 测试网节点运行在宿主机上。</p>\n<h4><a name=\"p-24112-demo-1-demo-check-22\" class=\"anchor\" href=\"#p-24112-demo-1-demo-check-22\" aria-label=\"Heading link\"></a>Demo 1: demo-check（环境检查 + 符号验证）</h4>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">docker run --rm --privileged --pid host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /root/ckb-testnet:/data \\\n  -v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n  ckb-probe:latest demo-check\n</code></pre>\n<p><strong>实际输出：</strong></p>\n<pre><code class=\"lang-auto\">════════════════════════════════════════════════════════════════\n  demo-check — environment + symbol report\n════════════════════════════════════════════════════════════════\n\n[1/3] running: ckb-probe check\n\n╔══════════════════════════════════════════════════════════════╗\n║  ckb-probe environment check                               ║\n╠══════════════════════════════════════════════════════════════╣\n  ✅ Kernel version            6.8.0-106-generic (need &gt;= 5.8)\n  ❌ BPF config                config not found\n  ✅ BTF support               /sys/kernel/btf/vmlinux exists\n  ✅ Permissions               running as root\n  ✅ bpf() syscall             available\n  ✅ uprobe support            /sys/kernel/debug/tracing/uprobe_events exists\n  ✅ CKB process               1 instance(s), pid=2349824\n  ❌ CKB symbols               no key rocksdb symbols found\n╚══════════════════════════════════════════════════════════════╝\n\n  Result: 6/8 checks passed\n\n╔══════════════════════════════════════════════════════════════╗\n║  ckb-probe eBPF validation                                 ║\n╠══════════════════════════════════════════════════════════════╣\n  ✅ ── uprobe latency ──      entry/return pair attach test\n  ✅   rocksdb_get_pinned_cf   entry + return attached\n  ✅   rocksdb_put             entry + return attached\n  ✅   rocksdb_write           entry + return attached\n  ✅   rocksdb_create_iterator_cf  entry + return attached\n  ✅ uprobe summary            latency pairs: 4/6, Tier 1 symbols: 15/19\n  ✅ kprobe tcp_sendmsg/tcp_recvmsg  attached\n  ✅ tracepoint sys_enter      attached to raw_syscalls/sys_enter\n╚══════════════════════════════════════════════════════════════╝\n\n  📊 Captured 264 uprobe, 40 tcp, 438 syscall events in 3s\n</code></pre>\n<blockquote>\n<p>注：Docker 容器内 <code>/proc/config.gz</code> 不可用，导致 BPF config 检查失败（<img src=\"https://talk.nervos.org/images/emoji/apple/cross_mark.png?v=15\" title=\":cross_mark:\" class=\"emoji\" alt=\":cross_mark:\" loading=\"lazy\" width=\"20\" height=\"20\">），但不影响实际 eBPF 功能。CKB symbols 检查在容器内因路径差异报 <img src=\"https://talk.nervos.org/images/emoji/apple/cross_mark.png?v=15\" title=\":cross_mark:\" class=\"emoji\" alt=\":cross_mark:\" loading=\"lazy\" width=\"20\" height=\"20\">，但 eBPF validation 部分确认了 15/19 个 Tier 1 符号实际可挂载。</p>\n</blockquote>\n<hr>\n<h4><a name=\"p-24112-demo-2-demo-table-23\" class=\"anchor\" href=\"#p-24112-demo-2-demo-table-23\" aria-label=\"Heading link\"></a>Demo 2: demo-table（实时统计表格）</h4>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">docker run --rm --privileged --pid host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /root/ckb-testnet:/data \\\n  -v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n  ckb-probe:latest demo-table 60\n</code></pre>\n<p><strong>实际输出：</strong></p>\n<pre><code class=\"lang-auto\">╭───────────────── CKB RocksDB Monitor (PID: 2349824) ─────────────────╮\n│ Uptime: 00:00:15   Sampling: 5s   Node: CKB v0.204.0               │\n├────────────┬───────┬──────────┬──────────┬──────────┬────────────────┤\n│ Operation  │  QPS  │ Avg(μs)  │ P50(μs)  │ P99(μs)  │    Bytes/s    │\n├────────────┼───────┼──────────┼──────────┼──────────┼────────────────┤\n│ GET        │   112 │  1671.8  │    12.3  │ 25165.8  │  12.0 KB/s    │\n│ PUT        │    11 │     6.3  │     6.1  │    24.6  │   1.5 KB/s    │\n│ WRITE      │     0 │    58.7  │    49.2  │    49.2  │       —       │\n│ ITER_NEW   │     0 │    21.5  │    24.6  │    24.6  │       —       │\n│ TXN_COMMIT │     0 │ 177592.5 │ 50331.6  │402653.2  │   1.5 KB/s    │\n╰────────────┴───────┴──────────┴──────────┴──────────┴────────────────╯\n  Status: ⏳ Warming up — Collecting baseline (285s remaining).\n</code></pre>\n<hr>\n<h4><a name=\"p-24112-demo-3-demo-histogram-24\" class=\"anchor\" href=\"#p-24112-demo-3-demo-histogram-24\" aria-label=\"Heading link\"></a>Demo 3: demo-histogram（延迟分布直方图）</h4>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">docker run --rm --privileged --pid host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /root/ckb-testnet:/data \\\n  -v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n  ckb-probe:latest demo-histogram 60\n</code></pre>\n<p><strong>实际输出：</strong></p>\n<pre><code class=\"lang-auto\">  GET latency distribution:\n         2μs │████                                         6\n         4μs │████████████████████████████████████████   404\n         8μs │███████████████                            150\n        16μs │██████████████████████                     212\n        32μs │████████████                                60\n        65μs │█                                            2\n       131μs │█                                            3\n\n  GET latency distribution (next cycle):\n         2μs │█                                            5\n         4μs │████████████████████████████████████████   215\n         8μs │█████████████                               72\n        16μs │████████████                                68\n        32μs │████████                                    42\n        65μs │█                                            3\n       131μs │                                             2\n</code></pre>\n<hr>\n<h4><a name=\"p-24112-demo-4-demo-slow-25\" class=\"anchor\" href=\"#p-24112-demo-4-demo-slow-25\" aria-label=\"Heading link\"></a>Demo 4: demo-slow（慢操作捕获）</h4>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">docker run --rm --privileged --pid host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /root/ckb-testnet:/data \\\n  -v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n  ckb-probe:latest demo-slow 60 1000\n</code></pre>\n<p>参数说明：<code>60</code> = 运行 60 秒，<code>1000</code> = 阈值 1000us</p>\n<p><strong>实际输出：</strong></p>\n<pre><code class=\"lang-auto\">╭───────────────── Slow Operations (threshold: 1000μs) ──────────────────╮\n│ Timestamp     │ Op         │   Latency │     Size │ Note               │\n├───────────────┼────────────┼───────────┼──────────┼────────────────────┤\n│ 18:25.870     │ GET        │   3,060μs │     32 B │                    │\n│ 18:25.892     │ GET        │  22,348μs │    240 B │                    │\n│ 18:25.928     │ GET        │  36,416μs │    125 B │                    │\n│ 18:25.953     │ GET        │  24,177μs │      8 B │                    │\n│ 18:25.956     │ GET        │   3,211μs │     32 B │                    │\n│ 18:26.006     │ GET        │  50,378μs │    240 B │                    │\n│ 18:26.042     │ GET        │  36,064μs │    101 B │                    │\n│ 18:26.068     │ GET        │  25,758μs │      8 B │                    │\n╰───────────────┴────────────┴───────────┴──────────┴────────────────────╯\n  Showing 8 of 157 slow operations in last 15s.\n  BPF event loss: 0 / 157 attempted  (0.0000%)\n</code></pre>\n<hr>\n<h4><a name=\"p-24112-demo-5-demo-normaljson-26\" class=\"anchor\" href=\"#p-24112-demo-5-demo-normaljson-26\" aria-label=\"Heading link\"></a>Demo 5: demo-normal（JSON 监控输出）</h4>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">docker run --rm --privileged --pid host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /root/ckb-testnet:/data \\\n  -v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n  -v /tmp/output:/tmp/perf-run \\\n  ckb-probe:latest demo-normal 60\n</code></pre>\n<p><strong>实际输出（最后一个采样周期）：</strong></p>\n<pre data-code-wrap=\"json\"><code class=\"lang-json\">{\n  \"anomalies\": [],\n  \"operations\": {\n    \"GET\": {\n      \"avg_us\": 421.02,\n      \"bytes_per_sec\": 5629,\n      \"p50_us\": 12.29,\n      \"p99_us\": 12582.91,\n      \"qps\": 50\n    },\n    \"ITER_NEW\": {\n      \"avg_us\": 33.57,\n      \"bytes_per_sec\": null,\n      \"p50_us\": 24.58,\n      \"p99_us\": 49.15,\n      \"qps\": 3\n    },\n    \"PUT\": {\n      \"avg_us\": 5.82,\n      \"bytes_per_sec\": 1676,\n      \"p50_us\": 6.14,\n      \"p99_us\": 24.58,\n      \"qps\": 13\n    },\n    \"TXN_COMMIT\": {\n      \"avg_us\": 54568.75,\n      \"bytes_per_sec\": 1676,\n      \"p50_us\": 786.43,\n      \"p99_us\": 201326.59,\n      \"qps\": 0\n    },\n    \"WRITE\": {\n      \"avg_us\": 51.8,\n      \"bytes_per_sec\": null,\n      \"p50_us\": 49.15,\n      \"p99_us\": 49.15,\n      \"qps\": 0\n    }\n  },\n  \"pid\": 2349824,\n  \"timestamp\": \"2026-05-02T07:52:39Z\",\n  \"uptime_secs\": 15\n}\n</code></pre>\n<p>输出保存到 <code>/tmp/perf-run/demo/demo-normal-snapshot.json</code>。</p>\n<hr>\n<h4><a name=\"p-24112-demo-6-demo-stress-27\" class=\"anchor\" href=\"#p-24112-demo-6-demo-stress-27\" aria-label=\"Heading link\"></a>Demo 6: demo-stress（压力注入 + 异常检测）</h4>\n<p><strong>命令：</strong></p>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">docker run --rm --privileged --pid host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /root/ckb-testnet:/data \\\n  -v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n  -v /tmp/output:/tmp/perf-run \\\n  ckb-probe:latest demo-stress 50000\n</code></pre>\n<p>参数说明：<code>50000</code> = db_bench 写入 50,000 条记录（每条 4KB，共 ~195MB）</p>\n<p><strong>实际输出：</strong></p>\n<pre><code class=\"lang-auto\">════════════════════════════════════════════════════════════════\n  demo-stress — synthetic RocksDB load injection (db_bench)\n════════════════════════════════════════════════════════════════\n  ckb pid       : 2349824\n  db_bench size : 50000 entries × 4KB = ~195 MB\n  output        : /tmp/perf-run/demo/demo-stress.txt\n\n[demo-stress] starting ckb-probe rocksdb --slow --threshold 500\n[demo-stress] ckb-probe pid=3548386\n[demo-stress] capturing 15s baseline...\n[demo-stress] launching db_bench fillrandom --num=50000 --threads=4\n[demo-stress] waiting for db_bench to complete...\n[demo-stress] db_bench done\n[demo-stress] 30s cool-down...\n\n════════════════════════════════════════════════════════════════\n  demo-stress result\n  2026-05-02 07:54:08\n════════════════════════════════════════════════════════════════\n\nckb-probe captured during stress:\n  ANOMALY DETECTED count : 0\n  slow op log lines      : 128\n  BPF event loss: 0 / 215 attempted  (0.0000%)\n\nNote: no ANOMALY DETECTED triggered. This can happen if the disk had\n      enough headroom to absorb db_bench without contending with CKB.\n      Try with a larger --num or apply db-options.aggressive via case-2.\n</code></pre>\n<blockquote>\n<p>注：本次测试磁盘有足够的 I/O headroom 吸收了 db_bench 负载，未触发 ANOMALY DETECTED。在磁盘 I/O 更紧张的环境下（或使用 aggressive RocksDB 调优），异常检测会被触发。Case 2 的压缩风暴测试已验证此能力（GET 延迟 35x 飙升，6,112 个慢操作）。</p>\n</blockquote>\n<hr>\n<h3><a name=\"p-24112-d4-docker-28\" class=\"anchor\" href=\"#p-24112-d4-docker-28\" aria-label=\"Heading link\"></a>D.4 三项长时间测试的 Docker 命令</h3>\n<h4><a name=\"p-24112-h-48h-s-1-s-4-29\" class=\"anchor\" href=\"#p-24112-h-48h-s-1-s-4-29\" aria-label=\"Heading link\"></a>48h 稳定性测试 (S-1 ~ S-4)</h4>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">docker run -d --name stability-test \\\n  --privileged --pid host --network host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /root/ckb-testnet:/data \\\n  -v /root/ckb-testnet/ckb:/root/ckb-testnet/ckb:ro \\\n  -v /tmp/perf-run:/tmp/perf-run \\\n  -e CKB_BIN=/root/ckb-testnet/ckb \\\n  -e CKB_RPC=http://127.0.0.1:8124 \\\n  ckb-probe:latest stability\n\n# 查看进度\ndocker logs -f stability-test\n\n# 测试完成后生成报告\ndocker exec stability-test bash -c \\\n  '/opt/scripts/stability/generate-report.sh /path/to/stability-&lt;timestamp&gt;/'\n</code></pre>\n<p>测试内容：48 小时持续运行，3 个 ckb-probe 实例并行采集，含 T+24h 的 CKB 进程重启恢复测试。</p>\n<h4><a name=\"p-24112-case-1-ibd-2-30\" class=\"anchor\" href=\"#p-24112-case-1-ibd-2-30\" aria-label=\"Heading link\"></a>Case 1: IBD 写入模式 (最长 2 小时)</h4>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">docker run --rm \\\n  --privileged --pid host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /root/ckb-testnet:/data \\\n  -v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n  -v /tmp/case-output:/tmp/perf-run \\\n  --entrypoint bash \\\n  ckb-probe:latest -c '\n    /opt/scripts/case/start-ckb.sh\n    /opt/scripts/case/case-1-ibd-write-pattern.sh 7200\n  '\n</code></pre>\n<p>脚本会自动在 tip 追上网络最新高度时提前退出。</p>\n<h4><a name=\"p-24112-case-2-30-31\" class=\"anchor\" href=\"#p-24112-case-2-30-31\" aria-label=\"Heading link\"></a>Case 2: 压缩风暴捕获 (最长 30 分钟)</h4>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">docker run --rm \\\n  --privileged --pid host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /root/ckb-testnet:/data \\\n  -v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n  -v /tmp/case-output:/tmp/perf-run \\\n  --entrypoint bash \\\n  ckb-probe:latest -c '\n    /opt/scripts/case/start-ckb.sh\n    /opt/scripts/case/case-2-compaction-storm.sh 1800\n  '\n</code></pre>\n<p>脚本会自动应用 aggressive RocksDB 调优、重启 CKB、挂载探针、等待慢操作数据，结束后自动恢复原始配置。</p>\n<h4><a name=\"p-24112-p-1-p-4-4-32\" class=\"anchor\" href=\"#p-24112-p-1-p-4-4-32\" aria-label=\"Heading link\"></a>P-1 ~ P-4 性能测试 (约 4 小时)</h4>\n<pre data-code-wrap=\"bash\"><code class=\"lang-bash\">docker run --rm \\\n  --privileged --pid host \\\n  -v /sys/kernel/debug:/sys/kernel/debug:ro \\\n  -v /sys/kernel/btf:/sys/kernel/btf:ro \\\n  -v /root/ckb-testnet:/data \\\n  -v /root/ckb-testnet/ckb:/usr/local/bin/ckb:ro \\\n  -v /tmp/perf-output:/tmp/perf-run \\\n  ckb-probe:latest perf\n</code></pre>\n<p>Phase A (2h with-probe) + Phase B (2h baseline)，均从相同 tip 启动，自动对比 CPU / RSS / 事件丢失 / 同步速度。</p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24113,
          "post_number": 52,
          "topic_id": 10008,
          "topic_title": "Spark Program | Ckb-probe: Deep Observability Tool for CKB Nodes Based on Aya Kernel eBPF/ckb-probe：基于 Aya 内核 eBPF 的 CKB 节点深度可观测性工具",
          "topic_slug": "spark-program-ckb-probe-deep-observability-tool-for-ckb-nodes-based-on-aya-kernel-ebpf-ckb-probe-aya-ebpf-ckb",
          "author": "clair",
          "created_at": "2026-05-02T08:19:48.293000+00:00",
          "updated_at": "2026-05-02T08:19:48.293000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/spark-program-ckb-probe-deep-observability-tool-for-ckb-nodes-based-on-aya-kernel-ebpf-ckb-probe-aya-ebpf-ckb/10008/52",
          "content_text": "Week 7 周报：JSON 全局输出优化 + 演示说明文档\n周期：2026-04-27 ~ 2026-05-03\n作者：Clair\n项目：ckb-probe — 基于 eBPF 的 CKB 全节点深度可观测性工具\n一、本周目标\nJSON 全局输出 — 确保所有模式的 JSON 输出格式统一、字段完整\n制作完整演示说明文档 — 结构化的文字演示报告（Markdown），覆盖五个演示流程步骤，附完整终端输出和说明\n二、完成情况\n交付项\n状态\n说明\nJSON --histogram 融合输出\n--json --histogram 联用时 JSON 包含 log2 延迟分布\nJSON 输出字段文档化\n全部字段含义、类型、取值范围写入演示文档\n演示说明文档（中文）\n五步流程 + 真实终端输出 + 解读 + Docker 构建与运行指南\nDocker 构建指南\n镜像构建、通用模板、卷挂载/权限说明\nDocker 六个 Demo 实际运行\n全部在 Docker 容器内执行并记录真实输出\nDocker 长时间测试命令\n48h 稳定性 / Case 1 / Case 2 / P-1~P-4 的完整 Docker 命令\nClippy 修复\nmanual_checked_ops 警告，改用 checked_div()\n三、JSON 全局输出优化\n3.1 现有 JSON 输出模式\nckb-probe 提供两种 JSON 输出：\n模式\n命令\n内容\nRocksDB 监控\nrocksdb --json\n每周期输出操作统计 + 异常事件\n符号分析\nsymbols --json\n完整的 ELF 符号分析报告\n3.2 本周改进：--json --histogram 融合\n改进前： --json 和 --histogram 为独立分支，--json 模式下直方图数据被忽略。\n改进后： --json --histogram 联用时，每个操作的 JSON 对象中增加 histogram 字段，包含非零 log2 桶的延迟分布：\n{\n\"operations\": {\n\"GET\": {\n\"qps\": 845,\n\"avg_us\": 24.97,\n\"p50_us\": 24.58,\n\"p99_us\": 98.30,\n\"bytes_per_sec\": 101976,\n\"histogram\": [\n{ \"ge_us\": 1.02, \"count\": 40 },\n{ \"ge_us\": 4.1, \"count\": 1528 },\n{ \"ge_us\": 8.19, \"count\": 421 },\n{ \"ge_us\": 16.38, \"count\": 727 },\n{ \"ge_us\": 32.77, \"count\": 125 },\n{ \"ge_us\": 65.54, \"count\": 22 }\n]\n}\n}\n}\n设计决策：\n仅在 --histogram 显式启用时输出 histogram 字段，避免默认 JSON 体积膨胀\n仅输出非零桶（count > 0），稀疏表示，典型场景下每操作 5~15 个桶\nge_us 表示该桶的下界（微秒），对应 2^i 纳秒转换\n不影响已有 JSON 消费者（新增字段，向后兼容）\n3.3 JSON 字段完整性审计\n字段\n类型\n说明\n模式\ntimestamp\nstring\nISO 8601 UTC\nrocksdb --json\npid\nnumber\n目标进程 PID\nrocksdb --json\nuptime_secs\nnumber\n运行时长（秒）\nrocksdb --json\noperations\nobject\n五个操作的指标\nrocksdb --json\noperations.*.qps\nnumber\n每秒操作数\nrocksdb --json\noperations.*.avg_us\nnumber\n平均延迟（微秒）\nrocksdb --json\noperations.*.p50_us\nnumber\nP50 延迟（微秒）\nrocksdb --json\noperations.*.p99_us\nnumber\nP99 延迟（微秒）\nrocksdb --json\noperations.*.bytes_per_sec\nnumber|null\n吞吐量（B/s）\nrocksdb --json\noperations.*.histogram\narray\nlog2 延迟分布\nrocksdb --json --histogram\nanomalies\narray\nEWMA 异常事件\nrocksdb --json\nanomalies.*.time\nstring\n相对时间\nrocksdb --json\nanomalies.*.type\nstring\n固定 “latency_spike”\nrocksdb --json\nanomalies.*.operation\nstring\n操作名\nrocksdb --json\nanomalies.*.trigger\nstring\n触发条件组合\nrocksdb --json\nanomalies.*.current_avg_us\nnumber\n当前均值\nrocksdb --json\nanomalies.*.baseline_avg_us\nnumber\n基线均值\nrocksdb --json\nanomalies.*.multiplier\nnumber\n偏离倍数\nrocksdb --json\nanomalies.*.current_p99_us\nnumber\n当前 P99\nrocksdb --json\nanomalies.*.baseline_p99_us\nnumber\n基线 P99\nrocksdb --json\n所有数值保留 2 位小数（round2()），bytes_per_sec 对 WRITE/ITER_NEW 为 null。\n四、演示说明文档\n已创建 docs/demo-walkthrough_zh.md，覆盖五个完整演示步骤：\n步骤\n演示\n对应命令\n内容\n1\n环境检查\ncheck / demo-check\neBPF 环境验证 + 符号分析\n2\n符号分析\nsymbols\nTier 1/2/3 符号分类 + 覆盖率\n3\n实时监控\ndemo-table / demo-histogram\n表格 + 延迟直方图\n4\n慢操作捕获\ndemo-slow\n超阈值操作实时列表 + BPF 丢失率\n5\nJSON 导出\n--json / --json --histogram\n标准 JSON + 直方图融合输出\n每个步骤包含：\n宿主机直接运行命令 + Docker 运行命令\n真实终端输出（2026-05-02 CKB v0.204.0 测试网节点）\n输出解读说明\n附录包含：\n附录 A/B/C：48h 稳定性 / Case Study / P-1~P-4 结果摘要\n附录 D：Docker 构建指南 + 通用运行模板 + 六个 Demo 的 Docker 命令与实际输出 + 三项长时间测试的 Docker 命令\n4.2 Docker 内六个 Demo 执行结果\n所有 Demo 均在 Docker 容器中实际执行并记录了真实输出：\nDemo\n命令\n关键结果\ndemo-check\nckb-probe:latest demo-check\n6/8 环境检查通过，15/19 Tier 1 符号可挂载，264 uprobe + 40 tcp + 438 syscall 事件\ndemo-table\nckb-probe:latest demo-table 60\nGET 93~177 QPS，PUT 8 QPS，TXN_COMMIT 326us\ndemo-histogram\nckb-probe:latest demo-histogram 60\nGET 双峰分布：主峰 4~32us，尾部 4~33ms\ndemo-slow\nckb-probe:latest demo-slow 60 1000\n157 个慢操作，最大 50,378us，BPF 丢失 0/157\ndemo-normal\nckb-probe:latest demo-normal 60\nJSON 快照输出，保存到 demo-normal-snapshot.json\ndemo-stress\nckb-probe:latest demo-stress 50000\n128 个慢操作，BPF 丢失 0/215，磁盘 headroom 充裕未触发 ANOMALY\n五、Clippy 修复\nCI 中 cargo clippy -- -D warnings 报出 manual_checked_ops 警告（Rust 1.95.0 新增 lint）：\nerror: manual checked division\n--> ckb-probe/src/commands/rocksdb.rs:814\n--> ckb-probe/src/commands/symbols.rs:572\n修复：将手动 if d == 0 { 0 } else { n / d } 模式改为 n.checked_div(d).unwrap_or(0)。\n六、交付物清单\n文件\n说明\ndocs/demo-walkthrough_zh.md\n五步演示 + Docker 指南 + 六个 Demo 实际输出\nckb-probe/src/commands/rocksdb.rs\nJSON --histogram 融合输出 + clippy 修复\nckb-probe/src/commands/symbols.rs\nclippy 修复\n六、后续计划\nWeek 8：发布与结项\n中英双语文档定稿 — 各类文档最终审校\nGitHub v0.1.0 Release — 打 tag、写 release notes、附带预编译 binary\n结项报告 — 按 main_proj.md 规范整理全部交付物、验收清单、已知限制\n社区分享 — 最终月度报告提交",
          "content_html": "<h1><a name=\"p-24113-week-7-json-1\" class=\"anchor\" href=\"#p-24113-week-7-json-1\" aria-label=\"Heading link\"></a>Week 7 周报：JSON 全局输出优化 + 演示说明文档</h1>\n<blockquote>\n<p>周期：2026-04-27 ~ 2026-05-03<br>\n作者：Clair<br>\n项目：ckb-probe — 基于 eBPF 的 CKB 全节点深度可观测性工具</p>\n</blockquote>\n<hr>\n<h2><a name=\"p-24113-h-2\" class=\"anchor\" href=\"#p-24113-h-2\" aria-label=\"Heading link\"></a>一、本周目标</h2>\n<ol>\n<li>JSON 全局输出 — 确保所有模式的 JSON 输出格式统一、字段完整</li>\n<li>制作完整演示说明文档 — 结构化的文字演示报告（Markdown），覆盖五个演示流程步骤，附完整终端输出和说明</li>\n</ol>\n<hr>\n<h2><a name=\"p-24113-h-3\" class=\"anchor\" href=\"#p-24113-h-3\" aria-label=\"Heading link\"></a>二、完成情况</h2>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>交付项</th>\n<th>状态</th>\n<th>说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>JSON --histogram 融合输出</td>\n<td><img src=\"https://talk.nervos.org/images/emoji/apple/white_check_mark.png?v=15\" title=\":white_check_mark:\" class=\"emoji only-emoji\" alt=\":white_check_mark:\" loading=\"lazy\" width=\"20\" height=\"20\"></td>\n<td><code>--json --histogram</code> 联用时 JSON 包含 log2 延迟分布</td>\n</tr>\n<tr>\n<td>JSON 输出字段文档化</td>\n<td><img src=\"https://talk.nervos.org/images/emoji/apple/white_check_mark.png?v=15\" title=\":white_check_mark:\" class=\"emoji only-emoji\" alt=\":white_check_mark:\" loading=\"lazy\" width=\"20\" height=\"20\"></td>\n<td>全部字段含义、类型、取值范围写入演示文档</td>\n</tr>\n<tr>\n<td>演示说明文档（中文）</td>\n<td><img src=\"https://talk.nervos.org/images/emoji/apple/white_check_mark.png?v=15\" title=\":white_check_mark:\" class=\"emoji only-emoji\" alt=\":white_check_mark:\" loading=\"lazy\" width=\"20\" height=\"20\"></td>\n<td>五步流程 + 真实终端输出 + 解读 + Docker 构建与运行指南</td>\n</tr>\n<tr>\n<td>Docker 构建指南</td>\n<td><img src=\"https://talk.nervos.org/images/emoji/apple/white_check_mark.png?v=15\" title=\":white_check_mark:\" class=\"emoji only-emoji\" alt=\":white_check_mark:\" loading=\"lazy\" width=\"20\" height=\"20\"></td>\n<td>镜像构建、通用模板、卷挂载/权限说明</td>\n</tr>\n<tr>\n<td>Docker 六个 Demo 实际运行</td>\n<td><img src=\"https://talk.nervos.org/images/emoji/apple/white_check_mark.png?v=15\" title=\":white_check_mark:\" class=\"emoji only-emoji\" alt=\":white_check_mark:\" loading=\"lazy\" width=\"20\" height=\"20\"></td>\n<td>全部在 Docker 容器内执行并记录真实输出</td>\n</tr>\n<tr>\n<td>Docker 长时间测试命令</td>\n<td><img src=\"https://talk.nervos.org/images/emoji/apple/white_check_mark.png?v=15\" title=\":white_check_mark:\" class=\"emoji only-emoji\" alt=\":white_check_mark:\" loading=\"lazy\" width=\"20\" height=\"20\"></td>\n<td>48h 稳定性 / Case 1 / Case 2 / P-1~P-4 的完整 Docker 命令</td>\n</tr>\n<tr>\n<td>Clippy 修复</td>\n<td><img src=\"https://talk.nervos.org/images/emoji/apple/white_check_mark.png?v=15\" title=\":white_check_mark:\" class=\"emoji only-emoji\" alt=\":white_check_mark:\" loading=\"lazy\" width=\"20\" height=\"20\"></td>\n<td><code>manual_checked_ops</code> 警告，改用 <code>checked_div()</code></td>\n</tr>\n</tbody>\n</table>\n</div><hr>\n<h2><a name=\"p-24113-json-4\" class=\"anchor\" href=\"#p-24113-json-4\" aria-label=\"Heading link\"></a>三、JSON 全局输出优化</h2>\n<h3><a name=\"p-24113-h-31-json-5\" class=\"anchor\" href=\"#p-24113-h-31-json-5\" aria-label=\"Heading link\"></a>3.1 现有 JSON 输出模式</h3>\n<p>ckb-probe 提供两种 JSON 输出：</p>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>模式</th>\n<th>命令</th>\n<th>内容</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>RocksDB 监控</td>\n<td><code>rocksdb --json</code></td>\n<td>每周期输出操作统计 + 异常事件</td>\n</tr>\n<tr>\n<td>符号分析</td>\n<td><code>symbols --json</code></td>\n<td>完整的 ELF 符号分析报告</td>\n</tr>\n</tbody>\n</table>\n</div><h3><a name=\"p-24113-h-32-json-histogram-6\" class=\"anchor\" href=\"#p-24113-h-32-json-histogram-6\" aria-label=\"Heading link\"></a>3.2 本周改进：<code>--json --histogram</code> 融合</h3>\n<p><strong>改进前：</strong> <code>--json</code> 和 <code>--histogram</code> 为独立分支，<code>--json</code> 模式下直方图数据被忽略。</p>\n<p><strong>改进后：</strong> <code>--json --histogram</code> 联用时，每个操作的 JSON 对象中增加 <code>histogram</code> 字段，包含非零 log2 桶的延迟分布：</p>\n<pre data-code-wrap=\"json\"><code class=\"lang-json\">{\n  \"operations\": {\n    \"GET\": {\n      \"qps\": 845,\n      \"avg_us\": 24.97,\n      \"p50_us\": 24.58,\n      \"p99_us\": 98.30,\n      \"bytes_per_sec\": 101976,\n      \"histogram\": [\n        { \"ge_us\": 1.02, \"count\": 40 },\n        { \"ge_us\": 4.1, \"count\": 1528 },\n        { \"ge_us\": 8.19, \"count\": 421 },\n        { \"ge_us\": 16.38, \"count\": 727 },\n        { \"ge_us\": 32.77, \"count\": 125 },\n        { \"ge_us\": 65.54, \"count\": 22 }\n      ]\n    }\n  }\n}\n</code></pre>\n<p><strong>设计决策：</strong></p>\n<ul>\n<li>仅在 <code>--histogram</code> 显式启用时输出 <code>histogram</code> 字段，避免默认 JSON 体积膨胀</li>\n<li>仅输出非零桶（<code>count &gt; 0</code>），稀疏表示，典型场景下每操作 5~15 个桶</li>\n<li><code>ge_us</code> 表示该桶的下界（微秒），对应 <code>2^i</code> 纳秒转换</li>\n<li>不影响已有 JSON 消费者（新增字段，向后兼容）</li>\n</ul>\n<h3><a name=\"p-24113-h-33-json-7\" class=\"anchor\" href=\"#p-24113-h-33-json-7\" aria-label=\"Heading link\"></a>3.3 JSON 字段完整性审计</h3>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>字段</th>\n<th>类型</th>\n<th>说明</th>\n<th>模式</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>timestamp</code></td>\n<td>string</td>\n<td>ISO 8601 UTC</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>pid</code></td>\n<td>number</td>\n<td>目标进程 PID</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>uptime_secs</code></td>\n<td>number</td>\n<td>运行时长（秒）</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>operations</code></td>\n<td>object</td>\n<td>五个操作的指标</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>operations.*.qps</code></td>\n<td>number</td>\n<td>每秒操作数</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>operations.*.avg_us</code></td>\n<td>number</td>\n<td>平均延迟（微秒）</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>operations.*.p50_us</code></td>\n<td>number</td>\n<td>P50 延迟（微秒）</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>operations.*.p99_us</code></td>\n<td>number</td>\n<td>P99 延迟（微秒）</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>operations.*.bytes_per_sec</code></td>\n<td>number|null</td>\n<td>吞吐量（B/s）</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>operations.*.histogram</code></td>\n<td>array</td>\n<td>log2 延迟分布</td>\n<td>rocksdb --json --histogram</td>\n</tr>\n<tr>\n<td><code>anomalies</code></td>\n<td>array</td>\n<td>EWMA 异常事件</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>anomalies.*.time</code></td>\n<td>string</td>\n<td>相对时间</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>anomalies.*.type</code></td>\n<td>string</td>\n<td>固定 “latency_spike”</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>anomalies.*.operation</code></td>\n<td>string</td>\n<td>操作名</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>anomalies.*.trigger</code></td>\n<td>string</td>\n<td>触发条件组合</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>anomalies.*.current_avg_us</code></td>\n<td>number</td>\n<td>当前均值</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>anomalies.*.baseline_avg_us</code></td>\n<td>number</td>\n<td>基线均值</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>anomalies.*.multiplier</code></td>\n<td>number</td>\n<td>偏离倍数</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>anomalies.*.current_p99_us</code></td>\n<td>number</td>\n<td>当前 P99</td>\n<td>rocksdb --json</td>\n</tr>\n<tr>\n<td><code>anomalies.*.baseline_p99_us</code></td>\n<td>number</td>\n<td>基线 P99</td>\n<td>rocksdb --json</td>\n</tr>\n</tbody>\n</table>\n</div><p>所有数值保留 2 位小数（<code>round2()</code>），<code>bytes_per_sec</code> 对 WRITE/ITER_NEW 为 null。</p>\n<hr>\n<h2><a name=\"p-24113-h-8\" class=\"anchor\" href=\"#p-24113-h-8\" aria-label=\"Heading link\"></a>四、演示说明文档</h2>\n<p>已创建 <code>docs/demo-walkthrough_zh.md</code>，覆盖五个完整演示步骤：</p>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>步骤</th>\n<th>演示</th>\n<th>对应命令</th>\n<th>内容</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1</td>\n<td>环境检查</td>\n<td><code>check</code> / <code>demo-check</code></td>\n<td>eBPF 环境验证 + 符号分析</td>\n</tr>\n<tr>\n<td>2</td>\n<td>符号分析</td>\n<td><code>symbols</code></td>\n<td>Tier 1/2/3 符号分类 + 覆盖率</td>\n</tr>\n<tr>\n<td>3</td>\n<td>实时监控</td>\n<td><code>demo-table</code> / <code>demo-histogram</code></td>\n<td>表格 + 延迟直方图</td>\n</tr>\n<tr>\n<td>4</td>\n<td>慢操作捕获</td>\n<td><code>demo-slow</code></td>\n<td>超阈值操作实时列表 + BPF 丢失率</td>\n</tr>\n<tr>\n<td>5</td>\n<td>JSON 导出</td>\n<td><code>--json</code> / <code>--json --histogram</code></td>\n<td>标准 JSON + 直方图融合输出</td>\n</tr>\n</tbody>\n</table>\n</div><p>每个步骤包含：</p>\n<ul>\n<li>宿主机直接运行命令 + Docker 运行命令</li>\n<li>真实终端输出（2026-05-02 CKB v0.204.0 测试网节点）</li>\n<li>输出解读说明</li>\n</ul>\n<p>附录包含：</p>\n<ul>\n<li><strong>附录 A/B/C</strong>：48h 稳定性 / Case Study / P-1~P-4 结果摘要</li>\n<li><strong>附录 D</strong>：Docker 构建指南 + 通用运行模板 + 六个 Demo 的 Docker 命令与实际输出 + 三项长时间测试的 Docker 命令</li>\n</ul>\n<h3><a name=\"p-24113-h-42-docker-demo-9\" class=\"anchor\" href=\"#p-24113-h-42-docker-demo-9\" aria-label=\"Heading link\"></a>4.2 Docker 内六个 Demo 执行结果</h3>\n<p>所有 Demo 均在 Docker 容器中实际执行并记录了真实输出：</p>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>Demo</th>\n<th>命令</th>\n<th>关键结果</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>demo-check</td>\n<td><code>ckb-probe:latest demo-check</code></td>\n<td>6/8 环境检查通过，15/19 Tier 1 符号可挂载，264 uprobe + 40 tcp + 438 syscall 事件</td>\n</tr>\n<tr>\n<td>demo-table</td>\n<td><code>ckb-probe:latest demo-table 60</code></td>\n<td>GET 93~177 QPS，PUT 8 QPS，TXN_COMMIT 326us</td>\n</tr>\n<tr>\n<td>demo-histogram</td>\n<td><code>ckb-probe:latest demo-histogram 60</code></td>\n<td>GET 双峰分布：主峰 4~32us，尾部 4~33ms</td>\n</tr>\n<tr>\n<td>demo-slow</td>\n<td><code>ckb-probe:latest demo-slow 60 1000</code></td>\n<td>157 个慢操作，最大 50,378us，BPF 丢失 0/157</td>\n</tr>\n<tr>\n<td>demo-normal</td>\n<td><code>ckb-probe:latest demo-normal 60</code></td>\n<td>JSON 快照输出，保存到 demo-normal-snapshot.json</td>\n</tr>\n<tr>\n<td>demo-stress</td>\n<td><code>ckb-probe:latest demo-stress 50000</code></td>\n<td>128 个慢操作，BPF 丢失 0/215，磁盘 headroom 充裕未触发 ANOMALY</td>\n</tr>\n</tbody>\n</table>\n</div><hr>\n<h2><a name=\"p-24113-clippy-10\" class=\"anchor\" href=\"#p-24113-clippy-10\" aria-label=\"Heading link\"></a>五、Clippy 修复</h2>\n<p>CI 中 <code>cargo clippy -- -D warnings</code> 报出 <code>manual_checked_ops</code> 警告（Rust 1.95.0 新增 lint）：</p>\n<pre><code class=\"lang-auto\">error: manual checked division\n  --&gt; ckb-probe/src/commands/rocksdb.rs:814\n  --&gt; ckb-probe/src/commands/symbols.rs:572\n</code></pre>\n<p>修复：将手动 <code>if d == 0 { 0 } else { n / d }</code> 模式改为 <code>n.checked_div(d).unwrap_or(0)</code>。</p>\n<hr>\n<h2><a name=\"p-24113-h-11\" class=\"anchor\" href=\"#p-24113-h-11\" aria-label=\"Heading link\"></a>六、交付物清单</h2>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>文件</th>\n<th>说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>docs/demo-walkthrough_zh.md</code></td>\n<td>五步演示 + Docker 指南 + 六个 Demo 实际输出</td>\n</tr>\n<tr>\n<td><code>ckb-probe/src/commands/rocksdb.rs</code></td>\n<td>JSON --histogram 融合输出 + clippy 修复</td>\n</tr>\n<tr>\n<td><code>ckb-probe/src/commands/symbols.rs</code></td>\n<td>clippy 修复</td>\n</tr>\n</tbody>\n</table>\n</div><hr>\n<h2><a name=\"p-24113-h-12\" class=\"anchor\" href=\"#p-24113-h-12\" aria-label=\"Heading link\"></a>六、后续计划</h2>\n<h3><a name=\"p-24113-week-8-13\" class=\"anchor\" href=\"#p-24113-week-8-13\" aria-label=\"Heading link\"></a>Week 8：发布与结项</h3>\n<ol>\n<li><strong>中英双语文档定稿</strong> — 各类文档最终审校</li>\n<li><strong>GitHub v0.1.0 Release</strong> — 打 tag、写 release notes、附带预编译 binary</li>\n<li><strong>结项报告</strong> — 按 main_proj.md 规范整理全部交付物、验收清单、已知限制</li>\n<li><strong>社区分享</strong> — 最终月度报告提交</li>\n</ol>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    },
    {
      "topic_id": 10225,
      "title": "iCKB Contracts Revisited: Old Code, New Audit",
      "slug": "ickb-contracts-revisited-old-code-new-audit",
      "url": "https://talk.nervos.org/t/ickb-contracts-revisited-old-code-new-audit/10225",
      "created_at": "2026-05-02T00:36:46.351000+00:00",
      "last_posted_at": "2026-05-02T01:33:02.680000+00:00",
      "category_id": 32,
      "tags": [],
      "posters": [
        "Original Poster",
        "Most Recent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24104,
          "post_number": 1,
          "topic_id": 10225,
          "topic_title": "iCKB Contracts Revisited: Old Code, New Audit",
          "topic_slug": "ickb-contracts-revisited-old-code-new-audit",
          "author": "phroi",
          "created_at": "2026-05-02T00:36:46.460000+00:00",
          "updated_at": "2026-05-02T00:36:46.460000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/ickb-contracts-revisited-old-code-new-audit/10225/1",
          "content_text": "This post mirrors the original security review report published in ickb/contracts: any question or feedback is more than welcomed\nReview completion date: 2026-05-01.\nReviewed contracts commit: 454cfa9. This is the last commit that changed scripts/contracts/** or scripts/Cargo.toml.\nExecutable test evidence: current scripts/tests/** suite in this repository state.\nScope: iCKB Logic, Owned Owner, Limit Order, and the shared utils crate.\nCross-references: the iCKB whitepaper and Nervos L1 reference implementations.\nPrior external audit: Scalebit (2024-09-10). That audit reported three issues: two informational and one minor.\nExecutive Summary\nUnder the current deployment assumptions, the review confirmed one live issue: the known Limit Order confusion attack.\niCKB Logic has a provenance-blind path: receiptless DAO-shaped outputs can later be treated as deposits, and a separately funded aggregate-deposit path can realize the split-vs-aggregate soft-cap spread.\nEven so, the current iCKB Logic tests do not show theft, duplicated principal, or a standalone profit path beyond assets the caller already controls.\nLimit Order remains vulnerable to phantom-order continuation, real-order stranding through fake match-state cells, and master rebinding when cloned or otherwise indistinguishable orders are cross-wired at mint or during match.\nOwned Owner preserves its pairing rules under the current whole-transaction-binding lock model; the remaining weak-lock claim-reassignment cases stay at the integration boundary.\nAll other candidate issues are blocked paths, generic CKB model constraints, or boundary cases relevant only to future integrations.\nFindings Summary\nOne known live issue remains in scope.\nID\nStatus\nComponent\nFinding\nLO-01\nKnown\nLimit Order\nCKB does not execute output locks at creation time, and limit_order accepts swapped mint pairings, so phantom and cross-wired order/master lineages can survive into later match or melt flows.\nProtocol Model and Assumptions\nThe component analyses below rely on the following protocol model and deployment assumptions.\niCKB is an inflation-protected CKB token (xUDT) that tokenizes NervosDAO deposits into a liquid, fungible asset. The protocol owns all CKB deposits in a shared pool. Users deposit CKB and receive iCKB; later, they can burn iCKB to withdraw from any mature deposit in that pool.\nThree on-chain scripts govern that flow:\niCKB Logic (dual-role): lock script on deposit cells, type script on receipt cells. Enforces the core balance equation and deposit-receipt accounting.\nOwned Owner: pairs withdrawal request cells with owner cells so users can claim NervosDAO phase 2 withdrawals.\nLimit Order: enables order-book-style exchange between CKB and UDTs, abstracting over NervosDAO and iCKB protocol constraints.\nKey Flows\nDeposit (two phases):\nPhase 1: CKB locked into NervosDAO deposit cells (lock = iCKB Logic, type = DAO). Receipts (type = iCKB Logic) track the deposits.\nPhase 2: Receipts converted to iCKB xUDT tokens using the deposit block’s accumulated rate (AR).\nWithdrawal:\nPhase 1: iCKB burned to release deposits from the pool into NervosDAO withdrawal requests.\nPhase 2: Standard NervosDAO withdrawal (outside iCKB scope).\nMixed transactions: A single transaction can combine deposit phase 1, phase 2, and withdrawal operations.\nThe next four execution rules explain why later findings hold or fail.\nScript Grouping\nMixed transactions execute iCKB Logic twice, but both runs see the same global cells and apply the same checks, so the dual execution does not create a desync path. CKB groups scripts by both hash and role. From script/src/types.rs:179-180:\nA cell can have a lock script and an optional type script. Even they reference the same script, lock script and type script will not be grouped together.\nLock groups and type groups are stored in separate BTreeMaps (types.rs:657-659). iCKB Logic uses the same {code_hash, Data1, empty_args} for both roles, so a mixed transaction produces one lock group for deposit cells and one type group for receipt cells.\nBoth groups still see the same global cell set (Source::Input and Source::Output, not group-local sources) and apply the same balance checks, so duplicate execution does not create a path where one run succeeds and the other fails.\nScript group construction at types.rs:716-740: lock groups are built from input locks only; type groups are built from both input and output types.\nxUDT Owner Mode\nxUDT owner mode stays within iCKB accounting because, in the deployed configuration, only two owner-mode routes are live and both co-execute iCKB Logic.\niCKB xUDT args are built as [ickb_logic_hash, XUDT_ARGS_FLAGS] with XUDT_ARGS_FLAGS = 0x80000000.\nRFC 0052’s owner-mode update has four triggers: matching input lock, matching input type, matching output type, and a witness owner_script whose hash matches the owner hash in args.\nIn the deployed configuration, the upstream xudt_rce.c flag parsing enables input lock by default, enables input type when flags & 0x80000000 is non-zero, and enables output type only when flags & 0x40000000 is non-zero. It also falls back to the witness owner_script path.\nThe witness owner_script path requires an exported validate symbol loaded via ckb_dlsym, while iCKB Logic is built as a CKB entrypoint (program_entry via ckb_std::entry!), not an xUDT validate extension. Under iCKB’s deployed args [ickb_logic_hash, 0x80000000], the live owner-mode paths are:\nA receipt (input type = iCKB Logic): needed for phase 2 minting\nA deposit (input lock = iCKB Logic): fires during withdrawal\nIn both cases iCKB Logic co-executes, as a type script for receipts or a lock script for deposits. Under this design, xUDT cannot enter owner mode without iCKB Logic also running.\nNervosDAO Interaction\nThe deposit phase 1 section of the iCKB whitepaper pins NervosDAO to the historical 814eb82 dao.c. That version enforces the known 64-output-cell limit with an output_withdrawing_mask bitset. iCKB inherits that as a platform constraint, but its own correctness does not depend on the limit.\nKey NervosDAO constraints confirmed against the whitepaper-pinned dao.c:\nWithdrawal request must be at the same output index as the consumed deposit.\nWithdrawal request capacity must equal the deposit capacity.\nWithdrawal request lock is not checked by validate_withdrawing_cell, but current CKB nodes still apply the DaoScriptSizeVerifier, so the withdrawing lock must at least match the consumed deposit lock’s serialized size.\nAR is read from deposit_data.dao[8], matching iCKB’s AR_OFFSET = 160 + 8.\nHeader Access\nHeader access explains why iCKB uses a two-phase deposit flow. From script/src/syscalls/load_header.rs:\nFor Source::Input: returns the header of the block containing the cell’s creation transaction. The block hash must appear in header_deps.\nFor Source::Output: always returns INDEX_OUT_OF_BOUND (load_header.rs:80). Deposits require two phases.\nTwo shared boundaries matter in the later sections: authorization and accounting.\nAuthorization Boundary\nSeveral candidate issues turn on the boundary between lock-script authorization and type-script accounting. The lock script / type script split means ownership is enforced by the user lock, while ickb_logic enforces value conservation. Its balance equation and cell classification never inspect who receives the output iCKB or the phase-1 DAO claim.\nUnder the current whole-transaction-binding user-lock assumption, that division is acceptable because the user’s signature commits to the full transaction. The deployment model used for this review assumes current user-facing iCKB flows use strong transaction-binding locks and does not treat delegated or adopted OTX flows as in-scope present-day integrations.\nThe weak-lock tests in this report do not replay a current wallet path. They model future or custom delegated, OTX, or other non-output-binding integrations, where recipient binding is an integration invariant rather than a guarantee provided by the iCKB contracts.\nExecuted regressions show why that stays a boundary case rather than a current finding:\nWeak-lock behavior: Recipient reassignment is possible in both iCKB Logic and Owned Owner. The phase-2 weak-lock redirect test and the withdrawal weak-lock redirect test demonstrate that weak-lock path.\nSigned phase-2 minting: Once sighash binds the full transaction, phase-2 redirects stop working. The phase-2 sighash binding test and the mixed phase-2 sighash binding test show that binding.\nSigned withdrawals: The same redirect pattern fails for withdrawal outputs once sighash binds the transaction. The withdrawal sighash binding test and the mixed withdrawal sighash binding test show the same result.\nWitness binding: The input-group signing test and the full-witness signing test confirm the witness-binding model used by the signed path.\nThe same ancillary scripts section already warns that delegated and OTX ownership patterns have their own pitfalls.\nAccounting Basis and Build Setting\nThe main accounting claims in this report rest on three properties:\nBalance equation: entry.rs:32 enforces in_udt + in_receipts == out_udt + in_deposits.\nDeposit-receipt accounting: entry.rs:132-137 requires deposited == receipted per amount bucket.\nOverflow checks: overflow-checks = true keeps the release-build accumulators from silently wrapping.\nTogether, these preserve protocol accounting across deposit, conversion, withdrawal, and mixed transactions.\nScope and Methodology\nThis section pins the reviewed sources and the checks behind the conclusions.\nReference Repositories\nRepository\nCommit\nickb/contracts\n454cfa9\nickb/whitepaper\ncdbabf6\nnervosnetwork/ckb\n6730f80\nnervosnetwork/ckb-system-scripts\n814eb82\nnervosnetwork/ckb-production-scripts\n26b0b4f\nnervosnetwork/rfcs\n4b502ff\nMethodology\nThe review prioritized executable behavior over static plausibility and classified issues by their concrete impact.\nReviewed the deployed release binaries and the transaction semantics they actually enforce, not just the latest source-level intent.\nReproduced script behavior locally with ckb-testtool, using executable transaction tests rather than relying on inspection alone.\nReused and extended the existing test suite, including replayed transaction shapes from observed protocol flows.\nComputed NervosDAO accounting with the exact DAO withdrawal math before classifying any claim-path discrepancy as a finding.\nSeparated findings that affect the current deployment from weak-lock assumptions, operator mistakes, or broader integration-only scenarios.\nRemoved or downgraded candidate issues that did not yield a harmful state transition, exploitable profit path, or realistic user loss.\nExplicitly tested mixed transactions and script-group interactions because iCKB safety depends on whole-transaction execution rather than isolated cell intent.\nTest Coverage\nA module wiring overview plus the test layout note show three layers:\nTest harness and utilities: root harness, fixtures, encoders, signing, and replay_helpers.\nScenario suite roots: ickb_logic, owned_owner, limit_order, and replay, each wiring topic-focused files under the matching subdirectory.\nHelper-focused unit coverage: helpers, which checks the shared encoders and witness/data builders used by the larger suites.\nA fresh cargo test -p tests run passed 214 tests with no failures. Those tests cover deployment-hash sanity checks, helper encodings, core flows, blocked-path regressions, and replayed transaction shapes across iCKB Logic, Owned Owner, and Limit Order.\nThe strong-lock regressions in ickb_logic, owned_owner, and signing replay secp256k1_blake160_sighash_all as the representative whole-transaction-binding lock. This repo does not include a QRL fixture or harness, so conclusions for other strong-lock deployments rely on the same binding property and the stated deployment assumptions rather than a separate in-repo replay.\nLimit Order\nThe deployed Limit Order binary still carries one live issue: the known confusion attack. No other candidate path in this component validates as a live issue.\nDesign\nLimit Order supports three operations: Mint (create order plus master), Match (partial or full fill), and Melt (destroy order plus master). Orders store exchange ratios (ckb_to_udt, udt_to_ckb) and a minimum match size.\nKey Validations\nValue conservation (entry.rs:103-105): uses C256 (checked U256) to prevent overflow.\nif i.ckb * ckb_mul + i.udt * udt_mul > o.ckb * ckb_mul + o.udt * udt_mul\nConcave ratio check (entry.rs:233-235): ensures round-trip conversion doesn’t lose value for the maker:\nif c2u.ckb_mul * u2c.udt_mul < c2u.udt_mul * u2c.ckb_mul\nMinimum match enforcement (entry.rs:108-129): prevents dust-level partial matches.\nStrict data length on execution (entry.rs:166): when limit_order executes, order data must be exactly UDT_SIZE + ORDER_SIZE bytes, so trailing data fails validation.\nAssessment\nExecuted tests confirm several live confusion manifestations under the current deployment assumptions, and separate tests bound the rebinding path.\nID\nStatus\nFinding\nLO-01\nKnown\nCKB does not execute output locks at creation time, and limit_order’s mint branch accepts swapped mint pairings, so mint-time output creation can seed phantom or cross-wired order/master lineages that later pass match or melt validation.\nConfirmed live manifestations:\nPhantom orders can be created without master validation: the phantom mint creation test.\nThat phantom lineage can then enter and keep advancing through fake match state without a real master: the phantom mint continuation test and the fake match lineage continuation test.\nA fake match-shaped order can melt against a real master and strand the real order: the real-order stranding test.\nCross-wired or cloned orders can rebind masters at mint or during match: the mint crosswire test and the cloned-order master-swap test.\nThe cloned-order continuation is reproduced with secp256k1_blake160_sighash_all-protected masters, so the live path is not a weak-lock-only artifact: the cloned-order master-swap test.\nBounding evidence: separate tests show that the rebinding path is narrower than arbitrary master rewriting:\nDiffering mint capacities and differing match progress both block cross-wiring: the distinct mint-capacity crosswire block test and the distinct match-progress crosswire block test.\nEven real orders fail to cross-wire arbitrarily, whether the checked info matches or differs: the same-info real-order crosswire block test and the different-info mainnet crosswire block test.\nThe UDT → CKB zero-UDT fulfilled-order shape still fails at the outer InvalidMatch check rather than surfacing a dedicated fulfilled-order guard.\niCKB Logic\nThe deployed iCKB Logic binary is provenance-blind at cell classification, but once a cell is inside the scripted flow it still preserves receipt and xUDT accounting. The subsections below explain both properties and why the currently executed provenance-blind paths still stop short of a confirmed theft or profit finding.\nCore Invariant\nentry.rs:32:\nif in_udt_ickb + in_receipts_ickb != out_udt_ickb + in_deposits_ickb {\nreturn Err(Error::AmountMismatch);\n}\nThis equation is the core accounting invariant across all flows:\nDeposit phase 1: 0 + 0 == 0 + 0 (deposits and receipts handled by accounting check only)\nDeposit phase 2: 0 + receipt_value == out_udt + 0\nWithdrawal: in_udt + 0 == out_udt + deposit_value\nMixed: any combination\nCell Classification\ncelltype.rs:60-82 classifies every cell in the transaction by examining lock and type script hashes, plus the DAO data shape when the DAO hash is present:\nLock\nType\nClassification\nLine\niCKB Logic\nDAO deposit (8 zero bytes)\nDeposit\nL69\niCKB Logic\nanything else\nScriptMisuse (error)\nL72\nother\niCKB Logic\nReceipt\nL75\nother\niCKB xUDT\nUdt\nL78\nDAO deposit (8 zero bytes) as lock\nany\nScriptMisuse (error)\nL62\niCKB xUDT as lock\nany\nScriptMisuse (error)\nL63\nother\nother\nUnknown (ignored)\nL81\nScriptType::None is only synthesized for missing type scripts; script_type() never returns None for locks, so the (ScriptType::None, _) arm is unreachable. NervosDAO withdrawal requests, which have non-zero data, correctly classify as Unknown via is_deposit_data.\nDeposit-Receipt Accounting (check_output)\nentry.rs:86-140 uses a BTreeMap<u64, Accounting> to ensure every group of same-sized output deposits is matched by equal receipt counts.\nOutput deposit: extract_unused_capacity → keyed by amount, deposited += 1\nOutput receipt: extract_receipt_data → keyed by deposit_amount, receipted += quantity\nFinal check at entry.rs:132-137: all entries must have deposited == receipted\nIt also validates:\nDeposits: 1000 CKB <= unoccupied_capacity <= 1M CKB (entry.rs:101-106, bounds at constants.rs:5-6)\nReceipts: deposit_quantity > 0 (entry.rs:114-116)\nUDT: amount <= u64::MAX (entry.rs:123-125)\niCKB Conversion (deposit_to_ickb)\nentry.rs:71-84 uses the same conversion for minting and withdrawal:\nlet ickb_amount = amount * ar_0 / ar_m;\nif ickb_amount > ICKB_SOFT_CAP_PER_DEPOSIT {\nreturn Ok(ickb_amount - (ickb_amount - ICKB_SOFT_CAP_PER_DEPOSIT) / 10);\n}\nDivision by zero: impossible (the RFC 0023 accumulated-rate rule sets AR_0 = 10 ^ 16 and AR_i = AR_{i-1} + floor(AR_{i-1} * s_i / C_{i-1}), so AR_m is non-zero).\nOverflow: u64 * u128 fits in u128 (~1.8e19 * 1e16 = ~1.8e35 < 3.4e38).\nPrecision: integer division loses at most 1 shannon per operation.\nFee/discount symmetry: the same function is used for both input receipts (fee, entry.rs:58-59) and input deposits (discount, entry.rs:52). The protocol breaks even: minted amount = burned amount.\nhas_empty_args Validation\nCell identification relies on the exact deployed script hash. utils/utils.rs:14-36 enforces empty args on:\nThe current script instance (covers input lock, input type, output type via CKB’s execution model)\nAll output locks matching the same code_hash + hash_type (utils.rs:29-31)\nOutput types don’t need explicit checking because they trigger execution and self-validate.\nAssessment\niCKB Logic has one state-admission blind spot plus several boundary points:\nProvenance blind spot: Receiptless DAO-shaped outputs can be admitted at output-lock creation time because CKB does not execute output locks, and later treated as pool deposits because cell_type_iter classifies any ickb_logic-locked, DAO-typed, deposit-data input as Deposit with no receipt-provenance check. The receiptless deposit-admission test confirms that admission-plus-later-classification path.\nAccepted spread path is still self-funded: When a separately provided split receipt is paired against a self-funded receiptless aggregate deposit, the contract accepts minting only the soft-cap valuation delta rather than the aggregate principal. The delta-only spread test and the oversized spread test show the accepted spread, while the deposit-alone spread block test blocks the deposit-alone variant.\nOrdinary mixed flows still apply the soft cap per receipt: The mixed phase1-phase2 soft-cap test shows that adding fresh phase-1 deposits in the same transaction does not turn this into a general aggregate soft-cap bypass.\nExecuted path limit: The narrowing comment in the phase-2 claim test and the self-funded principal claim test make the current limit explicit: the self-funded aggregate principal remains claimable in DAO phase 2, so the executed path does not show third-party principal theft or duplicated recovery.\nPrefix behavior: Trailing bytes in receipt and xUDT data reflect prefix-based parsing, while truncated encodings are still rejected. The receipt trailing-bytes tests, truncated receipt tests, and trailing/short xUDT output-data tests cover that behavior.\nWeak-lock boundary: Recipient-redirection scenarios remain boundary cases and do not apply under the current whole-transaction-binding user-lock assumption.\nRounding: Whole-CKB rounding claims remain false leads. The rounding mint test and the rounding withdrawal test fail unless exact shannon precision is used.\nOn current executable evidence, that provenance-blind path is real, but it still falls short of a confirmed theft or standalone profit finding.\nOwned Owner\nThe deployed Owned Owner binary preserves its pairing invariant under the current assumptions. The remaining questions concern which cells can be paired and who controls the pair at creation time.\nDesign\nOwned Owner pairs owned cells, namely NervosDAO withdrawal requests, with owner cells through a MetaPoint derived from the owner cell’s owned_distance field:\nMint: the owner cell stores a signed distance to the owned cell, so owned_index == owner_index + owned_distance.\nMelt: both cells must be consumed together.\nValidation\nFor inputs and outputs separately, the script enforces the same pairing rules:\nEach metapoint must have exactly owned == 1 and owner == 1 (entry.rs:57-60).\nOwned cells must be NervosDAO withdrawal requests: DAO type + non-zero data (entry.rs:45-47).\nA cell using the script as both lock and type is rejected (entry.rs:53).\nAssessment\nOwned Owner leaves four boundary points. The live claim-rotation path stays blocked in the currently modeled flows:\nLive claim rotation remains blocked: Attempts to roll a live claim into fresh Owned Owner pairs or to crosswire a fully DAO-constrained batch are rejected before a new live pairing survives. The fresh-pair rotation block test, new-pair rotation block test, and the DAO index-rule crosswire block test show that block.\nCrosswired later-claim ownership still depends on weak phase-1 authorization: When phase-1 owner outputs use weak or otherwise non-output-binding locks, later DAO claims can be reassigned across mixed foreign-plus-iCKB batches or fully iCKB batches. The mixed foreign-plus-iCKB weak-lock crosswire test, two-way weak-lock crosswire claim test, and three-way weak-lock crosswire claim test show that boundary case. Under the current strong-lock deployment assumption, this is not a present finding.\nForeign DAO withdrawal wrapping is allowed: The foreign DAO wrapping test shows that any DAO withdrawal request can be wrapped and later claimed, because the script checks only DAO type plus withdrawal-shaped data on the owned cell.\nCreator-side dead states are narrower than arbitrary malformed pairs: When Owned Owner actually executes as a type script, it rejects orphan and count-mismatch shapes, as shown by the orphan-owner rejection test and the two-owner mismatch test. But creation still accepts pairs whose owner lock never validated, as shown by the unspendable foreign-owner-lock test and the limit-order owner-lock stranding test. It also allows lock-only Owned Owner look-alikes that later fail on spend, as shown by the lock-only non-DAO look-alike test and the lock-only DAO-deposit look-alike test.\nDeployment Context and Documented Risks\nWitness Malleability (Documented)\nWitness malleability is a documented property, not a new finding. All three scripts use the script-as-lock (unsigned) plus script-as-type (controller) pattern, and none of them reads witnesses.\nThe whitepaper states the consequence directly: “if a script in a transaction needs to store data in the witness and this data can be tampered without the transaction becoming invalid, then this transaction must not employ the scripts presented in the current whitepaper.”\nNon-Upgradable Deployment\nDeployment is intentionally non-upgradable. The whitepaper’s non-upgradable deployment section says the scripts are deployed by data1, not by type, so they are non upgradable. Additionally, secp256k1_blake160 zero lock controls the binary.\nAny post-deployment bug requires migration to entirely new script deployments and a new dep group.\nConclusion\nUnder the current deployment assumptions, only the known Limit Order confusion attack remains live.\nThe iCKB Logic provenance-blind path exists, but the executed tests still stop at a self-funded edge case.\nThe remaining Owned Owner and cross-script cases are blocked or confined to integration/deployment boundaries.",
          "content_html": "<p><em>This post mirrors the <a href=\"https://github.com/ickb/contracts/blob/master/20260501-ICKB-Audit-Report.md\">original security review report</a> published in <code>ickb/contracts</code>: any question or feedback  is more than welcomed <img src=\"https://talk.nervos.org/images/emoji/apple/hugs.png?v=15\" title=\":hugs:\" class=\"emoji\" alt=\":hugs:\" loading=\"lazy\" width=\"20\" height=\"20\"></em></p>\n<ul>\n<li><strong>Review completion date:</strong> 2026-05-01.</li>\n<li><strong>Reviewed contracts commit:</strong> <a href=\"https://github.com/ickb/contracts/tree/454cfa966052a621c4e8b67001718c29ee8191a2\"><code>454cfa9</code></a>. This is the last commit that changed <code>scripts/contracts/**</code> or <code>scripts/Cargo.toml</code>.</li>\n<li><strong>Executable test evidence:</strong> current <code>scripts/tests/**</code> suite in this repository state.</li>\n<li><strong>Scope:</strong> <code>iCKB Logic</code>, <code>Owned Owner</code>, <code>Limit Order</code>, and the shared <code>utils</code> crate.</li>\n<li><strong>Cross-references:</strong> the <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md\">iCKB whitepaper</a> and Nervos L1 reference implementations.</li>\n<li><strong>Prior external audit:</strong> <a href=\"https://scalebit.xyz/reports/20240911-ICKB-Final-Audit-Report.pdf\">Scalebit (2024-09-10)</a>. That audit reported three issues: two informational and one minor.</li>\n</ul>\n<h2><a name=\"p-24104-executive-summary-1\" class=\"anchor\" href=\"#p-24104-executive-summary-1\" aria-label=\"Heading link\"></a>Executive Summary</h2>\n<p>Under the current deployment assumptions, the review confirmed one live issue: the known <code>Limit Order</code> confusion attack.</p>\n<ul>\n<li><code>iCKB Logic</code> has a provenance-blind path: receiptless DAO-shaped outputs can later be treated as deposits, and a separately funded aggregate-deposit path can realize the split-vs-aggregate soft-cap spread.</li>\n<li>Even so, the current <code>iCKB Logic</code> tests do not show theft, duplicated principal, or a standalone profit path beyond assets the caller already controls.</li>\n<li><code>Limit Order</code> remains vulnerable to phantom-order continuation, real-order stranding through fake match-state cells, and master rebinding when cloned or otherwise indistinguishable orders are cross-wired at mint or during match.</li>\n<li><code>Owned Owner</code> preserves its pairing rules under the current whole-transaction-binding lock model; the remaining weak-lock claim-reassignment cases stay at the integration boundary.</li>\n<li>All other candidate issues are blocked paths, generic CKB model constraints, or boundary cases relevant only to future integrations.</li>\n</ul>\n<h2><a name=\"p-24104-findings-summary-2\" class=\"anchor\" href=\"#p-24104-findings-summary-2\" aria-label=\"Heading link\"></a>Findings Summary</h2>\n<p>One known live issue remains in scope.</p>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>ID</th>\n<th>Status</th>\n<th>Component</th>\n<th>Finding</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>LO-01</td>\n<td>Known</td>\n<td><code>Limit Order</code></td>\n<td>CKB <a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L716-L739\">does not execute output locks at creation time</a>, and <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L71-L79\"><code>limit_order</code> accepts swapped mint pairings</a>, so phantom and cross-wired order/master lineages can survive into later match or melt flows.</td>\n</tr>\n</tbody>\n</table>\n</div><h2><a name=\"p-24104-protocol-model-and-assumptions-3\" class=\"anchor\" href=\"#p-24104-protocol-model-and-assumptions-3\" aria-label=\"Heading link\"></a>Protocol Model and Assumptions</h2>\n<p>The component analyses below rely on the following protocol model and deployment assumptions.</p>\n<p>iCKB is an inflation-protected CKB token (<code>xUDT</code>) that tokenizes NervosDAO deposits into a liquid, fungible asset. The protocol owns all CKB deposits in a shared pool. Users deposit CKB and receive iCKB; later, they can burn iCKB to withdraw from any mature deposit in that pool.</p>\n<p>Three on-chain scripts govern that flow:</p>\n<ol>\n<li><strong>iCKB Logic</strong> (dual-role): lock script on deposit cells, type script on receipt cells. Enforces the core balance equation and deposit-receipt accounting.</li>\n<li><strong>Owned Owner</strong>: pairs withdrawal request cells with owner cells so users can claim NervosDAO phase 2 withdrawals.</li>\n<li><strong>Limit Order</strong>: enables order-book-style exchange between CKB and UDTs, abstracting over NervosDAO and iCKB protocol constraints.</li>\n</ol>\n<h3><a name=\"p-24104-key-flows-4\" class=\"anchor\" href=\"#p-24104-key-flows-4\" aria-label=\"Heading link\"></a>Key Flows</h3>\n<p><strong>Deposit (two phases)</strong>:</p>\n<ul>\n<li>Phase 1: CKB locked into NervosDAO deposit cells (lock = iCKB Logic, type = DAO). Receipts (type = iCKB Logic) track the deposits.</li>\n<li>Phase 2: Receipts converted to iCKB <code>xUDT</code> tokens using the deposit block’s accumulated rate (AR).</li>\n</ul>\n<p><strong>Withdrawal</strong>:</p>\n<ul>\n<li>Phase 1: iCKB burned to release deposits from the pool into NervosDAO withdrawal requests.</li>\n<li>Phase 2: Standard NervosDAO withdrawal (outside iCKB scope).</li>\n</ul>\n<p><strong>Mixed transactions</strong>: A single transaction can combine deposit phase 1, phase 2, and withdrawal operations.</p>\n<p>The next four execution rules explain why later findings hold or fail.</p>\n<h3><a name=\"p-24104-script-grouping-5\" class=\"anchor\" href=\"#p-24104-script-grouping-5\" aria-label=\"Heading link\"></a>Script Grouping</h3>\n<p>Mixed transactions execute <code>iCKB Logic</code> twice, but both runs see the same global cells and apply the same checks, so the dual execution does not create a desync path. CKB groups scripts by both hash and role. From <a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L179-L180\"><code>script/src/types.rs:179-180</code></a>:</p>\n<blockquote>\n<p>A cell can have a lock script and an optional type script. Even they reference the same script, lock script and type script will not be grouped together.</p>\n</blockquote>\n<p>Lock groups and type groups are stored in separate <code>BTreeMap</code>s (<a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L657-L659\"><code>types.rs:657-659</code></a>). <code>iCKB Logic</code> uses the same <code>{code_hash, Data1, empty_args}</code> for both roles, so a mixed transaction produces one lock group for deposit cells and one type group for receipt cells.</p>\n<p>Both groups still see the same global cell set (<code>Source::Input</code> and <code>Source::Output</code>, not group-local sources) and apply the same balance checks, so duplicate execution does not create a path where one run succeeds and the other fails.</p>\n<p>Script group construction at <a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L716-L740\"><code>types.rs:716-740</code></a>: lock groups are built from input locks only; type groups are built from both input and output types.</p>\n<h3><a name=\"p-24104-xudt-owner-mode-6\" class=\"anchor\" href=\"#p-24104-xudt-owner-mode-6\" aria-label=\"Heading link\"></a>xUDT Owner Mode</h3>\n<p><code>xUDT</code> owner mode stays within iCKB accounting because, in the deployed configuration, only two owner-mode routes are live and both co-execute <code>iCKB Logic</code>.</p>\n<p>iCKB <code>xUDT</code> args are built as <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L116-L126\"><code>[ickb_logic_hash, XUDT_ARGS_FLAGS]</code></a> with <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/constants.rs#L1-L2\"><code>XUDT_ARGS_FLAGS = 0x80000000</code></a>.</p>\n<p>RFC 0052’s <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0052-extensible-udt/0052-extensible-udt.md#owner-mode-update\">owner-mode update</a> has four triggers: matching <code>input lock</code>, matching <code>input type</code>, matching <code>output type</code>, and a witness <code>owner_script</code> whose hash matches the owner hash in args.</p>\n<p>In the deployed configuration, the upstream <a href=\"https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L383-L458\"><code>xudt_rce.c</code> flag parsing</a> enables <code>input lock</code> by default, enables <code>input type</code> when <code>flags &amp; 0x80000000</code> is non-zero, and enables <code>output type</code> only when <code>flags &amp; 0x40000000</code> is non-zero. It also <a href=\"https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L645-L649\">falls back to the witness <code>owner_script</code> path</a>.</p>\n<p>The witness <code>owner_script</code> path requires an exported <a href=\"https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L36-L36\"><code>validate</code> symbol</a> loaded via <a href=\"https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L91-L113\"><code>ckb_dlsym</code></a>, while <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/main.rs#L23-L35\"><code>iCKB Logic</code></a> is built as a CKB entrypoint (<code>program_entry</code> via <code>ckb_std::entry!</code>), not an xUDT <code>validate</code> extension. Under iCKB’s deployed args <code>[ickb_logic_hash, 0x80000000]</code>, the live owner-mode paths are:</p>\n<ul>\n<li>A receipt (input type = iCKB Logic): needed for phase 2 minting</li>\n<li>A deposit (input lock = iCKB Logic): fires during withdrawal</li>\n</ul>\n<p>In both cases <code>iCKB Logic</code> co-executes, as a type script for receipts or a lock script for deposits. Under this design, <code>xUDT</code> cannot enter owner mode without <code>iCKB Logic</code> also running.</p>\n<h3><a name=\"p-24104-nervosdao-interaction-7\" class=\"anchor\" href=\"#p-24104-nervosdao-interaction-7\" aria-label=\"Heading link\"></a>NervosDAO Interaction</h3>\n<p>The <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#deposit-phase-1\">deposit phase 1 section of the iCKB whitepaper</a> pins <code>NervosDAO</code> to the historical <a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c\"><code>814eb82</code> <code>dao.c</code></a>. That version enforces the known <a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L565-L591\">64-output-cell limit</a> with an <a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L445\"><code>output_withdrawing_mask</code> bitset</a>. iCKB inherits that as a platform constraint, but its own correctness does not depend on the limit.</p>\n<p>Key NervosDAO constraints confirmed against the <a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c\">whitepaper-pinned <code>dao.c</code></a>:</p>\n<ul>\n<li>Withdrawal request must be at the <a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L518-L523\">same output index</a> as the consumed deposit.</li>\n<li>Withdrawal request capacity must <a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L356-L365\">equal the deposit capacity</a>.</li>\n<li>Withdrawal request lock is <a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L339-L385\">not checked by <code>validate_withdrawing_cell</code></a>, but current CKB nodes still apply the <a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/verification/src/transaction_verifier.rs#L811-L885\">DaoScriptSizeVerifier</a>, so the withdrawing lock must at least match the consumed deposit lock’s serialized size.</li>\n<li>AR is read from <a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L282-L283\"><code>deposit_data.dao[8]</code></a>, matching iCKB’s <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L51\"><code>AR_OFFSET = 160 + 8</code></a>.</li>\n</ul>\n<h3><a name=\"p-24104-header-access-8\" class=\"anchor\" href=\"#p-24104-header-access-8\" aria-label=\"Heading link\"></a>Header Access</h3>\n<p>Header access explains why iCKB uses a two-phase deposit flow. From <a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/syscalls/load_header.rs\"><code>script/src/syscalls/load_header.rs</code></a>:</p>\n<ul>\n<li>For <code>Source::Input</code>: returns the header of the block containing the cell’s creation transaction. The block hash must appear in <a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/syscalls/load_header.rs#L62-L66\"><code>header_deps</code></a>.</li>\n<li>For <code>Source::Output</code>: always returns <code>INDEX_OUT_OF_BOUND</code> (<a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/syscalls/load_header.rs#L80\"><code>load_header.rs:80</code></a>). Deposits require two phases.</li>\n</ul>\n<p>Two shared boundaries matter in the later sections: authorization and accounting.</p>\n<h3><a name=\"p-24104-authorization-boundary-9\" class=\"anchor\" href=\"#p-24104-authorization-boundary-9\" aria-label=\"Heading link\"></a>Authorization Boundary</h3>\n<p>Several candidate issues turn on the boundary between lock-script authorization and type-script accounting. The <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#lock-script\">lock script</a> / <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#type-script\">type script</a> split means ownership is enforced by the user lock, while <code>ickb_logic</code> enforces value conservation. Its <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L28-L34\">balance equation</a> and <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L69-L81\">cell classification</a> never inspect who receives the output <code>iCKB</code> or the phase-1 DAO claim.</p>\n<p>Under the <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#ancillary-scripts\">current whole-transaction-binding user-lock assumption</a>, that division is acceptable because the user’s signature commits to the full transaction. The deployment model used for this review assumes current user-facing iCKB flows use strong transaction-binding locks and does not treat delegated or adopted <code>OTX</code> flows as in-scope present-day integrations.</p>\n<p>The weak-lock tests in this report do not replay a current wallet path. They model future or custom delegated, <code>OTX</code>, or other non-output-binding integrations, where recipient binding is an integration invariant rather than a guarantee provided by the iCKB contracts.</p>\n<p>Executed regressions show why that stays a boundary case rather than a current finding:</p>\n<ul>\n<li><strong>Weak-lock behavior:</strong> Recipient reassignment is possible in both <code>iCKB Logic</code> and <code>Owned Owner</code>. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs#L5-L45\">phase-2 weak-lock redirect test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs#L6-L50\">withdrawal weak-lock redirect test</a> demonstrate that weak-lock path.</li>\n<li><strong>Signed phase-2 minting:</strong> Once <code>sighash</code> binds the full transaction, phase-2 redirects stop working. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs#L46-L98\">phase-2 sighash binding test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs#L99-L168\">mixed phase-2 sighash binding test</a> show that binding.</li>\n<li><strong>Signed withdrawals:</strong> The same redirect pattern fails for withdrawal outputs once <code>sighash</code> binds the transaction. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs#L51-L116\">withdrawal sighash binding test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs#L117-L246\">mixed withdrawal sighash binding test</a> show the same result.</li>\n<li><strong>Witness binding:</strong> The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/signing.rs#L88-L165\">input-group signing test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/signing.rs#L166-L215\">full-witness signing test</a> confirm the witness-binding model used by the signed path.</li>\n</ul>\n<p>The same <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#ancillary-scripts\">ancillary scripts section</a> already warns that delegated and <code>OTX</code> ownership patterns have their own pitfalls.</p>\n<h3><a name=\"p-24104-accounting-basis-and-build-setting-10\" class=\"anchor\" href=\"#p-24104-accounting-basis-and-build-setting-10\" aria-label=\"Heading link\"></a>Accounting Basis and Build Setting</h3>\n<p>The main accounting claims in this report rest on three properties:</p>\n<ol>\n<li><strong>Balance equation:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L32\"><code>entry.rs:32</code></a> enforces <code>in_udt + in_receipts == out_udt + in_deposits</code>.</li>\n<li><strong>Deposit-receipt accounting:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L132-L137\"><code>entry.rs:132-137</code></a> requires <code>deposited == receipted</code> per amount bucket.</li>\n<li><strong>Overflow checks:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/Cargo.toml#L6\"><code>overflow-checks = true</code></a> keeps the release-build accumulators from silently wrapping.</li>\n</ol>\n<p>Together, these preserve protocol accounting across deposit, conversion, withdrawal, and mixed transactions.</p>\n<h2><a name=\"p-24104-scope-and-methodology-11\" class=\"anchor\" href=\"#p-24104-scope-and-methodology-11\" aria-label=\"Heading link\"></a>Scope and Methodology</h2>\n<p>This section pins the reviewed sources and the checks behind the conclusions.</p>\n<h3><a name=\"p-24104-reference-repositories-12\" class=\"anchor\" href=\"#p-24104-reference-repositories-12\" aria-label=\"Heading link\"></a>Reference Repositories</h3>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>Repository</th>\n<th>Commit</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a href=\"https://github.com/ickb/contracts/tree/454cfa966052a621c4e8b67001718c29ee8191a2\">ickb/contracts</a></td>\n<td><a href=\"https://github.com/ickb/contracts/tree/454cfa966052a621c4e8b67001718c29ee8191a2\"><code>454cfa9</code></a></td>\n</tr>\n<tr>\n<td><a href=\"https://github.com/ickb/whitepaper/tree/cdbabf653ba98eacea397f94f8c894f32a538d6c\">ickb/whitepaper</a></td>\n<td><a href=\"https://github.com/ickb/whitepaper/tree/cdbabf653ba98eacea397f94f8c894f32a538d6c\"><code>cdbabf6</code></a></td>\n</tr>\n<tr>\n<td><a href=\"https://github.com/nervosnetwork/ckb/tree/6730f8023810d0888aa80c6a0d54cc2af918097d\">nervosnetwork/ckb</a></td>\n<td><a href=\"https://github.com/nervosnetwork/ckb/tree/6730f8023810d0888aa80c6a0d54cc2af918097d\"><code>6730f80</code></a></td>\n</tr>\n<tr>\n<td><a href=\"https://github.com/nervosnetwork/ckb-system-scripts/tree/814eb82c44f560dbdad2be97eb85464062920237\">nervosnetwork/ckb-system-scripts</a></td>\n<td><a href=\"https://github.com/nervosnetwork/ckb-system-scripts/tree/814eb82c44f560dbdad2be97eb85464062920237\"><code>814eb82</code></a></td>\n</tr>\n<tr>\n<td><a href=\"https://github.com/nervosnetwork/ckb-production-scripts/tree/26b0b4f15bb6eeb268b70d7ae006e244b7c06649\">nervosnetwork/ckb-production-scripts</a></td>\n<td><a href=\"https://github.com/nervosnetwork/ckb-production-scripts/tree/26b0b4f15bb6eeb268b70d7ae006e244b7c06649\"><code>26b0b4f</code></a></td>\n</tr>\n<tr>\n<td><a href=\"https://github.com/nervosnetwork/rfcs/tree/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe\">nervosnetwork/rfcs</a></td>\n<td><a href=\"https://github.com/nervosnetwork/rfcs/tree/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe\"><code>4b502ff</code></a></td>\n</tr>\n</tbody>\n</table>\n</div><h3><a name=\"p-24104-methodology-13\" class=\"anchor\" href=\"#p-24104-methodology-13\" aria-label=\"Heading link\"></a>Methodology</h3>\n<p>The review prioritized executable behavior over static plausibility and classified issues by their concrete impact.</p>\n<ul>\n<li>Reviewed the deployed release binaries and the transaction semantics they actually enforce, not just the latest source-level intent.</li>\n<li>Reproduced script behavior locally with <code>ckb-testtool</code>, using executable transaction tests rather than relying on inspection alone.</li>\n<li>Reused and extended the existing test suite, including replayed transaction shapes from observed protocol flows.</li>\n<li>Computed NervosDAO accounting with the exact DAO withdrawal math before classifying any claim-path discrepancy as a finding.</li>\n<li>Separated findings that affect the current deployment from weak-lock assumptions, operator mistakes, or broader integration-only scenarios.</li>\n<li>Removed or downgraded candidate issues that did not yield a harmful state transition, exploitable profit path, or realistic user loss.</li>\n<li>Explicitly tested mixed transactions and script-group interactions because iCKB safety depends on whole-transaction execution rather than isolated cell intent.</li>\n</ul>\n<h3><a name=\"p-24104-test-coverage-14\" class=\"anchor\" href=\"#p-24104-test-coverage-14\" aria-label=\"Heading link\"></a>Test Coverage</h3>\n<p>A <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests.rs\">module wiring overview</a> plus the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/README.md\">test layout note</a> show three layers:</p>\n<ul>\n<li><strong>Test harness and utilities:</strong> <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests.rs\">root harness</a>, <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/fixtures.rs\">fixtures</a>, <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/encoders.rs\">encoders</a>, <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/signing.rs\">signing</a>, and <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/replay_helpers.rs\">replay_helpers</a>.</li>\n<li><strong>Scenario suite roots:</strong> <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic.rs\">ickb_logic</a>, <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner.rs\">owned_owner</a>, <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order.rs\">limit_order</a>, and <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/replay.rs\">replay</a>, each wiring topic-focused files under the matching subdirectory.</li>\n<li><strong>Helper-focused unit coverage:</strong> <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/helpers.rs\">helpers</a>, which checks the shared encoders and witness/data builders used by the larger suites.</li>\n</ul>\n<p>A fresh <code>cargo test -p tests</code> run passed <code>214</code> tests with no failures. Those tests cover deployment-hash sanity checks, helper encodings, core flows, blocked-path regressions, and replayed transaction shapes across <code>iCKB Logic</code>, <code>Owned Owner</code>, and <code>Limit Order</code>.</p>\n<p>The strong-lock regressions in <code>ickb_logic</code>, <code>owned_owner</code>, and <code>signing</code> replay <code>secp256k1_blake160_sighash_all</code> as the representative whole-transaction-binding lock. This repo does not include a <code>QRL</code> fixture or harness, so conclusions for other strong-lock deployments rely on the same binding property and the stated deployment assumptions rather than a separate in-repo replay.</p>\n<hr>\n<h2><a name=\"p-24104-limit-order-15\" class=\"anchor\" href=\"#p-24104-limit-order-15\" aria-label=\"Heading link\"></a>Limit Order</h2>\n<p>The deployed <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs\"><code>Limit Order</code></a> binary still carries one live issue: the known confusion attack. No other candidate path in this component validates as a live issue.</p>\n<h3><a name=\"p-24104-design-16\" class=\"anchor\" href=\"#p-24104-design-16\" aria-label=\"Heading link\"></a>Design</h3>\n<p><code>Limit Order</code> supports three operations: <code>Mint</code> (create order plus master), <code>Match</code> (partial or full fill), and <code>Melt</code> (destroy order plus master). Orders store exchange ratios (<code>ckb_to_udt</code>, <code>udt_to_ckb</code>) and a minimum match size.</p>\n<h3><a name=\"p-24104-key-validations-17\" class=\"anchor\" href=\"#p-24104-key-validations-17\" aria-label=\"Heading link\"></a>Key Validations</h3>\n<p><strong>Value conservation</strong> (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L103-L105\"><code>entry.rs:103-105</code></a>): uses <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/c256.rs\"><code>C256</code></a> (checked U256) to prevent overflow.</p>\n<pre data-code-wrap=\"rust\"><code class=\"lang-rust\">if i.ckb * ckb_mul + i.udt * udt_mul &gt; o.ckb * ckb_mul + o.udt * udt_mul\n</code></pre>\n<p><strong>Concave ratio check</strong> (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L233-L235\"><code>entry.rs:233-235</code></a>): ensures round-trip conversion doesn’t lose value for the maker:</p>\n<pre data-code-wrap=\"rust\"><code class=\"lang-rust\">if c2u.ckb_mul * u2c.udt_mul &lt; c2u.udt_mul * u2c.ckb_mul\n</code></pre>\n<p><strong>Minimum match enforcement</strong> (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L108-L129\"><code>entry.rs:108-129</code></a>): prevents dust-level partial matches.</p>\n<p><strong>Strict data length on execution</strong> (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L166\"><code>entry.rs:166</code></a>): when <code>limit_order</code> executes, order data must be exactly <code>UDT_SIZE + ORDER_SIZE</code> bytes, so trailing data fails validation.</p>\n<h3><a name=\"p-24104-assessment-18\" class=\"anchor\" href=\"#p-24104-assessment-18\" aria-label=\"Heading link\"></a>Assessment</h3>\n<p>Executed tests confirm several live confusion manifestations under the current deployment assumptions, and separate tests bound the rebinding path.</p>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>ID</th>\n<th>Status</th>\n<th>Finding</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>LO-01</td>\n<td>Known</td>\n<td>CKB <a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L716-L739\">does not execute output locks at creation time</a>, and <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L71-L79\"><code>limit_order</code>’s mint branch</a> accepts swapped mint pairings, so mint-time output creation can seed phantom or cross-wired order/master lineages that later pass match or melt validation.</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Confirmed live manifestations:</strong></p>\n<ul>\n<li>Phantom orders can be created without master validation: the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/phantom_lineage.rs#L5-L36\">phantom mint creation test</a>.</li>\n<li>That phantom lineage can then enter and keep advancing through fake match state without a real master: the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/phantom_lineage.rs#L37-L74\">phantom mint continuation test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/fake_match_lineage.rs#L5-L62\">fake match lineage continuation test</a>.</li>\n<li>A fake match-shaped order can melt against a real master and strand the real order: the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/fake_match_lineage.rs#L63-L122\">real-order stranding test</a>.</li>\n<li>Cross-wired or cloned orders can rebind masters at mint or during match: the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs#L5-L118\">mint crosswire test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/crosswire_live_match.rs#L5-L84\">cloned-order master-swap test</a>.</li>\n<li>The cloned-order continuation is reproduced with <code>secp256k1_blake160_sighash_all</code>-protected masters, so the live path is not a weak-lock-only artifact: the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/crosswire_live_match.rs#L5-L84\">cloned-order master-swap test</a>.</li>\n</ul>\n<p><strong>Bounding evidence:</strong> separate tests show that the rebinding path is narrower than arbitrary master rewriting:</p>\n<ul>\n<li>Differing mint capacities and differing match progress both block cross-wiring: the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/crosswire_blockers.rs#L5-L55\">distinct mint-capacity crosswire block test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/crosswire_blockers.rs#L56-L152\">distinct match-progress crosswire block test</a>.</li>\n<li>Even real orders fail to cross-wire arbitrarily, whether the checked info matches or differs: the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/crosswire_blockers.rs#L153-L226\">same-info real-order crosswire block test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/crosswire_blockers.rs#L227-L364\">different-info mainnet crosswire block test</a>.</li>\n</ul>\n<p>The UDT → CKB zero-UDT fulfilled-order shape still fails at the outer <code>InvalidMatch</code> check rather than surfacing a dedicated fulfilled-order guard.</p>\n<hr>\n<h2><a name=\"p-24104-ickb-logic-19\" class=\"anchor\" href=\"#p-24104-ickb-logic-19\" aria-label=\"Heading link\"></a>iCKB Logic</h2>\n<p>The deployed <a href=\"https://github.com/ickb/contracts/tree/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src\"><code>iCKB Logic</code></a> binary is provenance-blind at cell classification, but once a cell is inside the scripted flow it still preserves receipt and <code>xUDT</code> accounting. The subsections below explain both properties and why the currently executed provenance-blind paths still stop short of a confirmed theft or profit finding.</p>\n<h3><a name=\"p-24104-core-invariant-20\" class=\"anchor\" href=\"#p-24104-core-invariant-20\" aria-label=\"Heading link\"></a>Core Invariant</h3>\n<p><a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L32\"><code>entry.rs:32</code></a>:</p>\n<pre data-code-wrap=\"rust\"><code class=\"lang-rust\">if in_udt_ickb + in_receipts_ickb != out_udt_ickb + in_deposits_ickb {\n    return Err(Error::AmountMismatch);\n}\n</code></pre>\n<p>This equation is the core accounting invariant across all flows:</p>\n<ul>\n<li><strong>Deposit phase 1</strong>: <code>0 + 0 == 0 + 0</code> (deposits and receipts handled by accounting check only)</li>\n<li><strong>Deposit phase 2</strong>: <code>0 + receipt_value == out_udt + 0</code></li>\n<li><strong>Withdrawal</strong>: <code>in_udt + 0 == out_udt + deposit_value</code></li>\n<li><strong>Mixed</strong>: any combination</li>\n</ul>\n<h3><a name=\"p-24104-cell-classification-21\" class=\"anchor\" href=\"#p-24104-cell-classification-21\" aria-label=\"Heading link\"></a>Cell Classification</h3>\n<p><a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L60-L82\"><code>celltype.rs:60-82</code></a> classifies every cell in the transaction by examining lock and type script hashes, plus the DAO data shape when the DAO hash is present:</p>\n<div class=\"md-table\">\n<table>\n<thead>\n<tr>\n<th>Lock</th>\n<th>Type</th>\n<th>Classification</th>\n<th>Line</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>iCKB Logic</td>\n<td>DAO deposit (8 zero bytes)</td>\n<td><code>Deposit</code></td>\n<td><a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L69\">L69</a></td>\n</tr>\n<tr>\n<td>iCKB Logic</td>\n<td>anything else</td>\n<td><code>ScriptMisuse</code> (error)</td>\n<td><a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L72\">L72</a></td>\n</tr>\n<tr>\n<td>other</td>\n<td>iCKB Logic</td>\n<td><code>Receipt</code></td>\n<td><a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L75\">L75</a></td>\n</tr>\n<tr>\n<td>other</td>\n<td>iCKB xUDT</td>\n<td><code>Udt</code></td>\n<td><a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L78\">L78</a></td>\n</tr>\n<tr>\n<td>DAO deposit (8 zero bytes) as lock</td>\n<td>any</td>\n<td><code>ScriptMisuse</code> (error)</td>\n<td><a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L62\">L62</a></td>\n</tr>\n<tr>\n<td>iCKB xUDT as lock</td>\n<td>any</td>\n<td><code>ScriptMisuse</code> (error)</td>\n<td><a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L63\">L63</a></td>\n</tr>\n<tr>\n<td>other</td>\n<td>other</td>\n<td><code>Unknown</code> (ignored)</td>\n<td><a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L81\">L81</a></td>\n</tr>\n</tbody>\n</table>\n</div><p><code>ScriptType::None</code> is only synthesized for <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L48-L50\">missing type scripts</a>; <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L95-L112\"><code>script_type()</code></a> never returns <code>None</code> for locks, so the <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L64\"><code>(ScriptType::None, _)</code></a> arm is unreachable. NervosDAO withdrawal requests, which have non-zero data, correctly classify as <code>Unknown</code> via <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/dao.rs#L17-L22\"><code>is_deposit_data</code></a>.</p>\n<h3><a name=\"p-24104-deposit-receipt-accounting-check_output-22\" class=\"anchor\" href=\"#p-24104-deposit-receipt-accounting-check_output-22\" aria-label=\"Heading link\"></a>Deposit-Receipt Accounting (<code>check_output</code>)</h3>\n<p><a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L86-L140\"><code>entry.rs:86-140</code></a> uses a <code>BTreeMap&lt;u64, Accounting&gt;</code> to ensure every group of same-sized output deposits is matched by equal receipt counts.</p>\n<ul>\n<li>Output deposit: <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L47-L49\"><code>extract_unused_capacity</code></a> → keyed by amount, <code>deposited += 1</code></li>\n<li>Output receipt: <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/utils.rs#L18-L40\"><code>extract_receipt_data</code></a> → keyed by <code>deposit_amount</code>, <code>receipted += quantity</code></li>\n<li>Final check at <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L132-L137\"><code>entry.rs:132-137</code></a>: all entries must have <code>deposited == receipted</code></li>\n</ul>\n<p>It also validates:</p>\n<ul>\n<li>Deposits: <code>1000 CKB &lt;= unoccupied_capacity &lt;= 1M CKB</code> (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L101-L106\"><code>entry.rs:101-106</code></a>, bounds at <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/constants.rs#L5-L6\"><code>constants.rs:5-6</code></a>)</li>\n<li>Receipts: <code>deposit_quantity &gt; 0</code> (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L114-L116\"><code>entry.rs:114-116</code></a>)</li>\n<li>UDT: <code>amount &lt;= u64::MAX</code> (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L123-L125\"><code>entry.rs:123-125</code></a>)</li>\n</ul>\n<h3><a name=\"p-24104-ickb-conversion-deposit_to_ickb-23\" class=\"anchor\" href=\"#p-24104-ickb-conversion-deposit_to_ickb-23\" aria-label=\"Heading link\"></a>iCKB Conversion (<code>deposit_to_ickb</code>)</h3>\n<p><a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L71-L84\"><code>entry.rs:71-84</code></a> uses the same conversion for minting and withdrawal:</p>\n<pre data-code-wrap=\"rust\"><code class=\"lang-rust\">let ickb_amount = amount * ar_0 / ar_m;\nif ickb_amount &gt; ICKB_SOFT_CAP_PER_DEPOSIT {\n    return Ok(ickb_amount - (ickb_amount - ICKB_SOFT_CAP_PER_DEPOSIT) / 10);\n}\n</code></pre>\n<ul>\n<li>Division by zero: impossible (the <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md#calculation\">RFC 0023 accumulated-rate rule</a> sets <code>AR_0 = 10 ^ 16</code> and <code>AR_i = AR_{i-1} + floor(AR_{i-1} * s_i / C_{i-1})</code>, so <code>AR_m</code> is non-zero).</li>\n<li>Overflow: <code>u64 * u128</code> fits in u128 (~1.8e19 * 1e16 = ~1.8e35 &lt; 3.4e38).</li>\n<li>Precision: integer division loses at most 1 shannon per operation.</li>\n<li>Fee/discount symmetry: the same function is used for both input receipts (fee, <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L58-L59\"><code>entry.rs:58-59</code></a>) and input deposits (discount, <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L52\"><code>entry.rs:52</code></a>). The protocol breaks even: minted amount = burned amount.</li>\n</ul>\n<h3><a name=\"p-24104-has_empty_args-validation-24\" class=\"anchor\" href=\"#p-24104-has_empty_args-validation-24\" aria-label=\"Heading link\"></a><code>has_empty_args</code> Validation</h3>\n<p>Cell identification relies on the exact deployed script hash. <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L14-L36\"><code>utils/utils.rs:14-36</code></a> enforces empty args on:</p>\n<ul>\n<li>The current script instance (covers input lock, input type, output type via CKB’s execution model)</li>\n<li>All output locks matching the same code_hash + hash_type (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L29-L31\"><code>utils.rs:29-31</code></a>)</li>\n</ul>\n<p>Output types don’t need explicit checking because they trigger execution and self-validate.</p>\n<h3><a name=\"p-24104-assessment-25\" class=\"anchor\" href=\"#p-24104-assessment-25\" aria-label=\"Heading link\"></a>Assessment</h3>\n<p><code>iCKB Logic</code> has one state-admission blind spot plus several boundary points:</p>\n<ul>\n<li><strong>Provenance blind spot:</strong> Receiptless DAO-shaped outputs can be admitted at output-lock creation time because CKB does not execute output locks, and later treated as pool deposits because <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L68-L75\"><code>cell_type_iter</code></a> classifies any <code>ickb_logic</code>-locked, DAO-typed, deposit-data input as <code>Deposit</code> with no receipt-provenance check. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L5-L78\">receiptless deposit-admission test</a> confirms that admission-plus-later-classification path.</li>\n<li><strong>Accepted spread path is still self-funded:</strong> When a separately provided split receipt is paired against a self-funded receiptless aggregate deposit, the contract accepts minting only the soft-cap valuation delta rather than the aggregate principal. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L79-L174\">delta-only spread test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L342-L423\">oversized spread test</a> show the accepted spread, while the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L297-L341\">deposit-alone spread block test</a> blocks the deposit-alone variant.</li>\n<li><strong>Ordinary mixed flows still apply the soft cap per receipt:</strong> The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/soft_cap.rs#L154-L233\">mixed phase1-phase2 soft-cap test</a> shows that adding fresh phase-1 deposits in the same transaction does not turn this into a general aggregate soft-cap bypass.</li>\n<li><strong>Executed path limit:</strong> The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L175-L296\">narrowing comment in the phase-2 claim test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L175-L296\">self-funded principal claim test</a> make the current limit explicit: the self-funded aggregate principal remains claimable in DAO phase 2, so the executed path does not show third-party principal theft or duplicated recovery.</li>\n<li><strong>Prefix behavior:</strong> Trailing bytes in receipt and <code>xUDT</code> data reflect prefix-based parsing, while truncated encodings are still rejected. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs#L5-L84\">receipt trailing-bytes tests</a>, <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs#L85-L155\">truncated receipt tests</a>, and <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs#L5-L112\">trailing/short <code>xUDT</code> output-data tests</a> cover that behavior.</li>\n<li><strong>Weak-lock boundary:</strong> Recipient-redirection scenarios remain boundary cases and do not apply under the current <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#ancillary-scripts\">whole-transaction-binding user-lock assumption</a>.</li>\n<li><strong>Rounding:</strong> Whole-CKB rounding claims remain false leads. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/economic_precision.rs#L5-L92\">rounding mint test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/economic_precision.rs#L93-L227\">rounding withdrawal test</a> fail unless exact shannon precision is used.</li>\n</ul>\n<p>On current executable evidence, that provenance-blind path is real, but it still falls short of a confirmed theft or standalone profit finding.</p>\n<hr>\n<h2><a name=\"p-24104-owned-owner-26\" class=\"anchor\" href=\"#p-24104-owned-owner-26\" aria-label=\"Heading link\"></a>Owned Owner</h2>\n<p>The deployed <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/owned_owner/src/entry.rs\"><code>Owned Owner</code></a> binary preserves its pairing invariant under the current assumptions. The remaining questions concern which cells can be paired and who controls the pair at creation time.</p>\n<h3><a name=\"p-24104-design-27\" class=\"anchor\" href=\"#p-24104-design-27\" aria-label=\"Heading link\"></a>Design</h3>\n<p><code>Owned Owner</code> pairs owned cells, namely NervosDAO withdrawal requests, with owner cells through a <code>MetaPoint</code> derived from the owner cell’s <code>owned_distance</code> field:</p>\n<ul>\n<li><strong>Mint:</strong> the owner cell stores a signed distance to the owned cell, so <code>owned_index == owner_index + owned_distance</code>.</li>\n<li><strong>Melt:</strong> both cells must be consumed together.</li>\n</ul>\n<h3><a name=\"p-24104-validation-28\" class=\"anchor\" href=\"#p-24104-validation-28\" aria-label=\"Heading link\"></a>Validation</h3>\n<p>For inputs and outputs separately, the script enforces the same pairing rules:</p>\n<ul>\n<li>Each metapoint must have exactly <code>owned == 1</code> and <code>owner == 1</code> (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/owned_owner/src/entry.rs#L57-L60\"><code>entry.rs:57-60</code></a>).</li>\n<li>Owned cells must be NervosDAO withdrawal requests: DAO type + non-zero data (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/owned_owner/src/entry.rs#L45-L47\"><code>entry.rs:45-47</code></a>).</li>\n<li>A cell using the script as both lock and type is rejected (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/owned_owner/src/entry.rs#L53\"><code>entry.rs:53</code></a>).</li>\n</ul>\n<h3><a name=\"p-24104-assessment-29\" class=\"anchor\" href=\"#p-24104-assessment-29\" aria-label=\"Heading link\"></a>Assessment</h3>\n<p><code>Owned Owner</code> leaves four boundary points. The live claim-rotation path stays blocked in the currently modeled flows:</p>\n<ul>\n<li><strong>Live claim rotation remains blocked:</strong> Attempts to roll a live claim into fresh <code>Owned Owner</code> pairs or to crosswire a fully DAO-constrained batch are rejected before a new live pairing survives. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs#L6-L78\">fresh-pair rotation block test</a>, <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs#L79-L254\">new-pair rotation block test</a>, and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs#L5-L89\">DAO index-rule crosswire block test</a> show that block.</li>\n<li><strong>Crosswired later-claim ownership still depends on weak phase-1 authorization:</strong> When phase-1 owner outputs use weak or otherwise non-output-binding locks, later DAO claims can be reassigned across mixed foreign-plus-iCKB batches or fully iCKB batches. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs#L5-L190\">mixed foreign-plus-iCKB weak-lock crosswire test</a>, <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs#L176-L335\">two-way weak-lock crosswire claim test</a>, and <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs#L336-L469\">three-way weak-lock crosswire claim test</a> show that boundary case. Under the current strong-lock deployment assumption, this is not a present finding.</li>\n<li><strong>Foreign DAO withdrawal wrapping is allowed:</strong> The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs#L6-L114\">foreign DAO wrapping test</a> shows that any DAO withdrawal request can be wrapped and later claimed, because the script checks only DAO type plus withdrawal-shaped data on the owned cell.</li>\n<li><strong>Creator-side dead states are narrower than arbitrary malformed pairs:</strong> When <code>Owned Owner</code> actually executes as a type script, it rejects orphan and count-mismatch shapes, as shown by the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/pair_formation.rs#L260-L289\">orphan-owner rejection test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/pair_formation.rs#L107-L178\">two-owner mismatch test</a>. But creation still accepts pairs whose owner lock never validated, as shown by the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs#L6-L100\">unspendable foreign-owner-lock test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs#L101-L196\">limit-order owner-lock stranding test</a>. It also allows lock-only <code>Owned Owner</code> look-alikes that later fail on spend, as shown by the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/script_misuse.rs#L144-L184\">lock-only non-DAO look-alike test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/script_misuse.rs#L185-L226\">lock-only DAO-deposit look-alike test</a>.</li>\n</ul>\n<hr>\n<h2><a name=\"p-24104-deployment-context-and-documented-risks-30\" class=\"anchor\" href=\"#p-24104-deployment-context-and-documented-risks-30\" aria-label=\"Heading link\"></a>Deployment Context and Documented Risks</h2>\n<h3><a name=\"p-24104-witness-malleability-documented-31\" class=\"anchor\" href=\"#p-24104-witness-malleability-documented-31\" aria-label=\"Heading link\"></a>Witness Malleability (Documented)</h3>\n<p>Witness malleability is a documented property, not a new finding. All three scripts use the script-as-lock (unsigned) plus script-as-type (controller) pattern, and none of them reads witnesses.</p>\n<p>The <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#unsigned-lock-witnesses-malleability\">whitepaper states the consequence directly</a>: “if a script in a transaction needs to store data in the witness and this data can be tampered without the transaction becoming invalid, then this transaction must not employ the scripts presented in the current whitepaper.”</p>\n<h3><a name=\"p-24104-non-upgradable-deployment-32\" class=\"anchor\" href=\"#p-24104-non-upgradable-deployment-32\" aria-label=\"Heading link\"></a>Non-Upgradable Deployment</h3>\n<p>Deployment is intentionally non-upgradable. The whitepaper’s <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#non-upgradable-deployment\">non-upgradable deployment section</a> says the scripts are deployed  by <code>data1</code>, not by type, so they are non upgradable. Additionally, <code>secp256k1_blake160</code> zero lock controls the binary.</p>\n<p>Any post-deployment bug requires migration to entirely new script deployments and a new dep group.</p>\n<hr>\n<h2><a name=\"p-24104-conclusion-33\" class=\"anchor\" href=\"#p-24104-conclusion-33\" aria-label=\"Heading link\"></a>Conclusion</h2>\n<p>Under the current deployment assumptions, only the known <code>Limit Order</code> confusion attack remains live.</p>\n<p>The <code>iCKB Logic</code> provenance-blind path exists, but the executed tests still stop at a self-funded edge case.</p>\n<p>The remaining <code>Owned Owner</code> and cross-script cases are blocked or confined to integration/deployment boundaries.</p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24105,
          "post_number": 2,
          "topic_id": 10225,
          "topic_title": "iCKB Contracts Revisited: Old Code, New Audit",
          "topic_slug": "ickb-contracts-revisited-old-code-new-audit",
          "author": "phroi",
          "created_at": "2026-05-02T00:37:05.260000+00:00",
          "updated_at": "2026-05-02T00:37:05.260000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/ickb-contracts-revisited-old-code-new-audit/10225/2",
          "content_text": "Appendix: Scenario Analysis\nThe appendix records the case-by-case traces that support the component assessments and the findings summary.\nClass 1: Token Inflation (minting iCKB without backing)\nThese scenarios test whether iCKB can be created without the corresponding deposit-side accounting.\n1A. Direct xUDT minting bypass\nAttack: trigger xUDT owner mode without iCKB Logic validation.\nTrace: under iCKB’s deployed [ickb_logic_hash, XUDT_ARGS_FLAGS] with XUDT_ARGS_FLAGS = 0x80000000, xUDT owner mode has two live iCKB routes: a matching input type for receipts and a matching input lock for deposits (RFC 0052, xudt_rce.c).\nThe only other upstream owner-mode route is the witness owner_script fallback, but that path looks up the exported validate symbol via ckb_dlsym. iCKB Logic is built as a CKB entrypoint instead of an xUDT extension. In the two live cases, iCKB Logic co-executes, so the balance equation still applies. The output-witness owner-script fallback test and the input-witness owner-script fallback test reproduce that attempted route and still fail under xUDT amount checks.\nResult: Blocked.\n1B. Forge a high-value receipt\nAttack: create a receipt claiming more deposits than actually exist.\nTrace: check_output accounting requires deposited == receipted per amount in a BTreeMap. The over-counted receipt test shows that a receipt cannot claim more same-sized deposits than the transaction actually creates.\nResult: Blocked.\n1C. Inflate receipt value via AR manipulation\nAttack: make a receipt appear to be from an older block (lower AR = higher iCKB value).\nTrace: extract_accumulated_rate calls load_header, which reads the block hash from CellMeta.transaction_info.block_hash and only succeeds when that block is also present in header_deps. The transaction creator cannot override that linkage.\nResult: Blocked.\n1D. Create receipt without prior deposits\nAttack: consume a “receipt” that was never backed by actual deposits.\nTrace: the receipt uses iCKB Logic as its type script. Creating it as an output triggers iCKB Logic, which validates deposit-receipt accounting. CKB’s UTXO model then makes the created cell immutable. No valid receipt can exist without corresponding deposits.\nResult: Blocked.\nClass 2: Token Theft (unauthorized withdrawal)\nThese scenarios test whether pool deposits can be released without paying the corresponding iCKB cost.\n2A. Withdraw deposits without burning iCKB\nAttack: consume a deposit cell without providing sufficient iCKB.\nTrace: the balance equation (entry.rs:32) requires in_udt + in_receipts == out_udt + in_deposits. With no UDT or receipts on input: 0 + 0 != 0 + deposit_value → AmountMismatch.\nResult: Blocked.\n2B. Bypass iCKB Logic during deposit consumption\nAttack: consume a deposit cell through NervosDAO directly, without iCKB Logic running.\nTrace: deposits use iCKB Logic as their lock. CKB always executes input lock scripts (the lock-script rule), so there is no way to consume the input without triggering that lock.\nResult: Blocked.\n2C. Exploit cell_dep for value extraction\nAttack: reference a deposit as a cell_dep to extract data without consuming it.\nTrace: cells used in cell_deps remain live and are not considered dead like inputs. CKB executes lock scripts for inputs and type scripts for inputs and outputs, so referencing a deposit as a cell dep neither consumes it nor triggers its scripts.\nResult: No attack vector.\nClass 3: Economic Exploitation\nThese paths matter only if they create a repeatable profit or a material pool imbalance.\n3A. Oversized deposit fee/discount arbitrage\nAttack: deposit oversized, get iCKB with a 10% fee, then immediately withdraw the same deposit with a 10% discount.\nTrace: both fee and discount use the same deposit_to_ickb function with the same parameters. For a deposit at block M:\nPhase 2 mints: deposit_to_ickb(amount, AR_m) = X iCKB\nWithdrawal costs: deposit_to_ickb(amount, AR_m) = X iCKB\nNet profit = 0.\nResult: No arbitrage. Fee and discount are symmetric by construction.\n3B. Cherry-pick cheapest deposits\nAttack: scan the pool for deposits that require the least nominal iCKB to withdraw and then withdraw those deposits first.\nTrace: deposit_to_ickb computes amount * AR_0 / AR_m. RFC 0023’s maximum-withdrawable-capacity formula scales the later DAO claim by AR_n / AR_m, and the whitepaper’s exchange-rate calculation values the same deposit from block m at 100000 CKB * 10 ^ 16 / AR_m iCKB, excluding occupied capacity.\nDeposits with higher AR_m require less nominal iCKB because the formula values them lower in iCKB, not because the pool applies a discount.\nResult: No mispricing. Each deposit is priced by the same formula, up to integer-division rounding.\n3C. Integer rounding exploitation\nAttack: create many small deposits to accumulate rounding errors.\nTrace: the rounding mint test and the rounding withdrawal test show that the reported whole-CKB or rounded claims fail with AmountMismatch unless the exact shannon-precision value is used. The supposed extraction path does not validate on chain.\nResult: Blocked by exact shannon-precision accounting.\nClass 4: Data Manipulation\nThese cases test whether malformed cells can enter the accounting flow with misleading metadata.\n4A. Receipt with zero deposit_quantity\nTrace: entry.rs:114-116 rejects zero-quantity receipts. The zero-quantity receipt test shows the output creation failure directly, so input receipts with zero quantity cannot exist as live cells.\nResult: Blocked.\n4B. Receipt amount without matching deposit\nTrace: check_output uses a BTreeMap keyed by deposit_amount. The over-counted receipt test shows that a receipt cannot claim more same-sized deposits than the transaction actually creates, and the unmatched receipt-amount test shows that a receipt amount with no matching deposit bucket yields ReceiptMismatch.\nResult: Blocked.\n4C. Cell with iCKB Logic lock + non-DAO type\nTrace: once iCKB Logic executes, celltype.rs:72 rejects (ScriptType::IckbLogic, _) with ScriptMisuse. The lock-only non-DAO output test shows that such an output can still be created because output locks do not execute at creation time, but spending it later fails with ScriptMisuse.\nResult: Cannot be spent successfully.\n4D. NervosDAO withdrawal request classified as deposit\nTrace: is_deposit_data checks for exactly 8 zero bytes. Withdrawal requests have non-zero data that stores the block number, so they fall through to ScriptType::Unknown and then CellType::Unknown.\nResult: Blocked.\n4E. Deposit capacity manipulation\nAttack: inflate extract_unused_capacity by manipulating cell fields.\nTrace: CKB requires occupied capacity to fit within cell capacity, and extract_unused_capacity subtracts that VM-computed occupied capacity from the actual cell capacity. For the standard iCKB deposit shape, the whitepaper’s exchange-rate calculation uses c_o = 82 CKB. That occupied capacity is fixed by the deposit structure, not chosen independently by the attacker.\nResult: Blocked.\n4F. Deposit interest/maturity reset (whitepaper#18)\nAttack: consume an iCKB deposit and create a new deposit at the same output index, effectively resetting the deposit’s age and accrued interest in the pool. This would lower pool-wide returns at minimal cost.\nTrace: the specific same-index reset described here is blocked by NervosDAO phase 1. The receiptless aggregate-deposit variant is a different claim.\nNervosDAO blocks it: when a DAO deposit is consumed, validate_withdrawing_cell requires the output at the same index to be a withdrawal request with non-zero data containing the deposit block number. A new deposit with 8 zero bytes fails the stored_block_number != deposit_header.block_number check because genesis block number 0 does not match the real deposit block. The transaction is rejected.\nBy contrast, the broader provenance-blind path is a different claim. The receiptless deposit-admission test shows that ickb_logic later accepts a receiptless DAO-shaped output as a structurally valid deposit input once it exists.\nThe delta-only spread test and the oversized spread test show that the contract accepts a self-funded soft-cap spread, while the deposit-alone spread block test blocks the deposit-only variant.\nThe narrowing comment in the phase-2 claim test and the self-funded principal claim test make the limit explicit: the executed path still does not prove receipt-backed-principal theft or duplicated recovery.\nSo the specific “same output index” reset is blocked by NervosDAO. The receiptless aggregate-deposit variant stays a self-funded provenance-blind edge case rather than a confirmed double-claim exploit.\nResult: Blocked for the same-index reset described here. The receiptless aggregate-deposit path exists, but the current tests still stop short of proving receipt-backed-principal theft or duplicated recovery.\nClass 5: Cross-Script Interactions\nThese scenarios check whether behavior that is safe in isolation breaks once multiple scripts share a transaction.\n5A. Witness malleability during withdrawal (whitepaper#22, credit: @XuJiandong)\nAttack: tamper with witness data for the iCKB Logic lock group (unsigned lock). All three witness fields in the group (lock, input_type, output_type) are malleable because iCKB Logic does not use signature-based verification.\nTrace: iCKB Logic does not read witnesses. NervosDAO does read input_type from the witness to locate the deposit header (dao.c:63-98). If an attacker tampers with that header index, NervosDAO later compares the claimed deposit block number with the actual deposit header and fails at deposited_block_number != deposit_data.block_number.\nThe iCKB malformed witness test and the Owned Owner malformed witness test reproduce that malformed header-index witness failure path in iCKB Logic and Owned Owner withdrawal flows.\nThe whitepaper’s unsigned-lock-witnesses section already documents that general malleability risk and warns against combining these scripts with witness-dependent logic.\nResult: Can cause transaction failure (griefing), cannot cause fund loss. This is a liveness issue, not a safety issue. Documented in the whitepaper.\n5B. Separate lock/type group execution desync\nAttack: exploit dual execution in the hope that one run passes while the other fails.\nTrace: CKB requires ALL script groups to pass (the verifier loop returns an error if any verify_script_group(...) call fails). Both lock and type executions see identical cells at absolute indices and perform the same balance checks. If either fails, the transaction is rejected.\nResult: Blocked.\n5C. Non-empty-args iCKB Logic variant\nAttack: create a cell with {iCKB Logic code_hash, Data1, [0x01]} as type, hoping to bypass validation.\nTrace: different args produce a different script hash, so the cell is not recognized by script_type(). Even if it executes as its own type group, it still fails has_empty_args(). The non-empty-args poisoning regressions in phase2_sibling_classification.rs cover both output-sibling and input-sibling variants.\nResult: Blocked.\n5D. Orphaned Owned Owner cell\nTrace: owned_owner/entry.rs:57-60 requires every metapoint to have exactly owned==1, owner==1. The orphan-owner rejection test shows that an orphan type-script owner cell is rejected immediately. A separate lock-only orphan case can still be created at output-lock creation time and later strand, as shown by the orphan withdrawal-request dead-state test.\nResult: Blocked when Owned Owner executes. Lock-only look-alikes can still be created and later fail.\n5E. Limit Order value decrease\nTrace: limit_order/entry.rs:103-105 enforces value conservation with C256 (checked U256). Any decrease is rejected.\nResult: Blocked.\n5F. Limit Order confusion attack\nTrace: CKB builds lock groups only from input locks, while type groups come from both input and output types (types.rs:716-739). A limit-order cell is the lock-only (true, false) case in limit_order/entry.rs:48-56, so an attacker can create phantom order outputs with arbitrary master outpoints without running limit_order at creation time. One manifestation is a fake order that shares a real master outpoint; if a user later melts the wrong order, the real order becomes permanently stranded.\nResult: Known vulnerability. Documented in whitepaper. The real-order stranding test confirms the later real-order stranding path on the deployed binary.\nThe whitepaper’s mitigation is front-end lineage checking from the original mint transaction. Under the deployed lock-only design, the chain does not validate phantom orders at creation time because the order cell is created as an output lock-only cell.\nClass 6: Edge Cases\nThe remaining scenarios are boundary checks, platform constraints, or known economic limitations.\n6A. Boundary values\nTrace: the minimum deposit check uses < (entry.rs:101), so exactly 1000 CKB is allowed. The maximum uses > (entry.rs:104), so exactly 1M CKB is also allowed. The boundary-value regressions in deposit_bounds.rs cover both edges.\nResult: Correct.\n6B. u128 overflow in balance equation\nTrace: overflow-checks = true is enabled in scripts/Cargo.toml. Overflow panics and rejects the transaction.\nResult: Blocked (by the compiler setting and practical bounds).\n6C. Division by zero in deposit_to_ickb\nTrace: the RFC 0023 accumulated-rate rule sets AR_0 = 10 ^ 16 and AR_i = AR_{i-1} + floor(AR_{i-1} * s_i / C_{i-1}), so every deposit header has non-zero AR_m. deposit_to_ickb cannot divide by zero.\nResult: Impossible.\n6D. extract_unused_capacity underflow\nTrace: CKB VM enforces capacity >= occupied_capacity for all cells. The subtraction at utils.rs:48 is safe.\nResult: Impossible.\n6E. Chain reorganization between deposit phases (whitepaper#15)\nAttack: deposit phase 1 is included in block B. Before phase 2, a chain reorg removes B. The phase 2 transaction still references B’s header in header_deps, but B no longer exists in the canonical chain.\nTrace: CKB consensus requires all blocks listed in header_deps to exist in the canonical chain (RFC 0022: “the transaction can only be added to the chain if all the block listed in header_deps are already in the chain (uncles excluded)”). If B is reorged out, then (a) the phase 1 deposit cell no longer exists as a live cell, so it cannot be referenced, and (b) the header_dep pointing to B is invalid. The phase 2 transaction is rejected.\nResult: Blocked by CKB consensus rules. Reorgs cannot create phantom deposits.\n6F. Busywork / pool dilution attack (whitepaper#8)\nAttack: an attacker with large capital repeatedly deposits CKB in standard deposits and then withdraws, cycling through the pool. This shifts the maturity distribution: the remaining deposits are younger, so users must wait longer for a mature deposit.\nTrace: the attack requires sustained capital commitment. Per the whitepaper analysis, controlling the first available epoch requires about 0.6% of pool capital, while controlling the first 3 days requires about 10%. With a 0.3% APR per 180 epochs, a user blocked for 1 epoch loses about 0.0017% interest.\nThe attacker earns nothing because the cycled CKB returns to them, still pays transaction fees, and must lock capital for 180 epochs per cycle. As the pool grows, the capital requirement rises proportionally while the impact per unit of capital falls.\nResult: Requires sustained capital and yields less impact as the pool grows. This is a known limitation, not a vulnerability.\n6G. Same-block receipt and deposit consumption\nAttack: create a deposit plus receipt in TX1, then consume both in TX2 (receipt for phase 2 plus deposit for withdrawal) in the hope that the AR difference yields free iCKB.\nTrace: both were created in the same block (TX1). extract_accumulated_rate returns the same AR for both. Since receipt_value == deposit_value, the balance equation yields 0 + receipt_value == out_udt + deposit_value → out_udt = 0. No net iCKB is minted.\nResult: No profit.\n6H. Race between receipt creation and deposit withdrawal\nScenario: a user creates deposit D plus receipt R in phase 1. Before the user performs phase 2, someone else withdraws D.\nTrace: R still exists and is valid, and its iCKB value is fixed by the creation-block AR. D being consumed by someone else is expected pool behavior, so the user still converts R to iCKB normally in phase 2.\nThe protocol remains balanced because the withdrawer paid deposit_to_ickb(D) iCKB, and the receipt holder receives the equivalent receipt_iCKB_value(R).\nResult: Pool accounting stays balanced.",
          "content_html": "<h2><a name=\"p-24105-appendix-scenario-analysis-1\" class=\"anchor\" href=\"#p-24105-appendix-scenario-analysis-1\" aria-label=\"Heading link\"></a>Appendix: Scenario Analysis</h2>\n<p>The appendix records the case-by-case traces that support the component assessments and the findings summary.</p>\n<h3><a name=\"p-24105-class-1-token-inflation-minting-ickb-without-backing-2\" class=\"anchor\" href=\"#p-24105-class-1-token-inflation-minting-ickb-without-backing-2\" aria-label=\"Heading link\"></a>Class 1: Token Inflation (minting iCKB without backing)</h3>\n<p>These scenarios test whether iCKB can be created without the corresponding deposit-side accounting.</p>\n<p><strong>1A. Direct xUDT minting bypass</strong></p>\n<p><strong>Attack:</strong> trigger xUDT owner mode without <code>iCKB Logic</code> validation.</p>\n<p><strong>Trace:</strong> under iCKB’s deployed <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L116-L126\"><code>[ickb_logic_hash, XUDT_ARGS_FLAGS]</code></a> with <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/constants.rs#L1-L2\"><code>XUDT_ARGS_FLAGS = 0x80000000</code></a>, <code>xUDT</code> owner mode has two live iCKB routes: a matching input type for receipts and a matching input lock for deposits (<a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0052-extensible-udt/0052-extensible-udt.md#owner-mode-update\">RFC 0052</a>, <a href=\"https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L383-L458\"><code>xudt_rce.c</code></a>).</p>\n<p>The only other upstream owner-mode route is the witness <a href=\"https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L645-L649\"><code>owner_script</code> fallback</a>, but that path looks up the exported <a href=\"https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L36-L36\"><code>validate</code> symbol</a> via <a href=\"https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L91-L113\"><code>ckb_dlsym</code></a>. <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/main.rs#L23-L35\"><code>iCKB Logic</code></a> is built as a CKB entrypoint instead of an xUDT extension. In the two live cases, <code>iCKB Logic</code> co-executes, so the balance equation still applies. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs#L5-L38\">output-witness owner-script fallback test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs#L39-L71\">input-witness owner-script fallback test</a> reproduce that attempted route and still fail under <code>xUDT</code> amount checks.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>1B. Forge a high-value receipt</strong></p>\n<p><strong>Attack:</strong> create a receipt claiming more deposits than actually exist.</p>\n<p><strong>Trace:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L86-L140\"><code>check_output</code></a> accounting requires <code>deposited == receipted</code> per amount in a <code>BTreeMap</code>. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receipt_matching.rs#L42-L78\">over-counted receipt test</a> shows that a receipt cannot claim more same-sized deposits than the transaction actually creates.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>1C. Inflate receipt value via AR manipulation</strong></p>\n<p><strong>Attack:</strong> make a receipt appear to be from an older block (lower AR = higher <code>iCKB</code> value).</p>\n<p><strong>Trace:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L54-L61\"><code>extract_accumulated_rate</code></a> calls <code>load_header</code>, which reads the block hash from <a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/syscalls/load_header.rs#L57-L61\"><code>CellMeta.transaction_info.block_hash</code></a> and only succeeds when that block is also present in <a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/syscalls/load_header.rs#L62-L66\"><code>header_deps</code></a>. The transaction creator cannot override that linkage.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>1D. Create receipt without prior deposits</strong></p>\n<p><strong>Attack:</strong> consume a “receipt” that was never backed by actual deposits.</p>\n<p><strong>Trace:</strong> the receipt uses <code>iCKB Logic</code> as its type script. Creating it as an output triggers <code>iCKB Logic</code>, which validates deposit-receipt accounting. CKB’s <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#value-storage\">UTXO model</a> then makes the created cell immutable. No valid receipt can exist without corresponding deposits.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<h3><a name=\"p-24105-class-2-token-theft-unauthorized-withdrawal-3\" class=\"anchor\" href=\"#p-24105-class-2-token-theft-unauthorized-withdrawal-3\" aria-label=\"Heading link\"></a>Class 2: Token Theft (unauthorized withdrawal)</h3>\n<p>These scenarios test whether pool deposits can be released without paying the corresponding iCKB cost.</p>\n<p><strong>2A. Withdraw deposits without burning iCKB</strong></p>\n<p><strong>Attack:</strong> consume a deposit cell without providing sufficient <code>iCKB</code>.</p>\n<p><strong>Trace:</strong> the balance equation (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L32\"><code>entry.rs:32</code></a>) requires <code>in_udt + in_receipts == out_udt + in_deposits</code>. With no UDT or receipts on input: <code>0 + 0 != 0 + deposit_value</code> → <code>AmountMismatch</code>.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>2B. Bypass iCKB Logic during deposit consumption</strong></p>\n<p><strong>Attack:</strong> consume a deposit cell through <code>NervosDAO</code> directly, without <code>iCKB Logic</code> running.</p>\n<p><strong>Trace:</strong> deposits use <code>iCKB Logic</code> as their lock. CKB always executes input lock scripts (the <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#lock-script\">lock-script rule</a>), so there is no way to consume the input without triggering that lock.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>2C. Exploit cell_dep for value extraction</strong></p>\n<p><strong>Attack:</strong> reference a deposit as a <code>cell_dep</code> to extract data without consuming it.</p>\n<p><strong>Trace:</strong> cells used in <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#code-locating\"><code>cell_deps</code></a> remain live and are <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#code-locating\">not considered dead like inputs</a>. CKB executes <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#lock-script\">lock scripts for inputs</a> and <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#type-script\">type scripts for inputs and outputs</a>, so referencing a deposit as a cell dep neither consumes it nor triggers its scripts.</p>\n<p><strong>Result:</strong> <strong>No attack vector.</strong></p>\n<h3><a name=\"p-24105-class-3-economic-exploitation-4\" class=\"anchor\" href=\"#p-24105-class-3-economic-exploitation-4\" aria-label=\"Heading link\"></a>Class 3: Economic Exploitation</h3>\n<p>These paths matter only if they create a repeatable profit or a material pool imbalance.</p>\n<p><strong>3A. Oversized deposit fee/discount arbitrage</strong></p>\n<p><strong>Attack:</strong> deposit oversized, get <code>iCKB</code> with a 10% fee, then immediately withdraw the same deposit with a 10% discount.</p>\n<p><strong>Trace:</strong> both fee and discount use the same <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L71-L84\"><code>deposit_to_ickb</code></a> function with the same parameters. For a deposit at block <code>M</code>:</p>\n<ul>\n<li>Phase 2 mints: <code>deposit_to_ickb(amount, AR_m)</code> = X iCKB</li>\n<li>Withdrawal costs: <code>deposit_to_ickb(amount, AR_m)</code> = X iCKB</li>\n</ul>\n<p>Net profit = 0.</p>\n<p><strong>Result:</strong> <strong>No arbitrage.</strong> Fee and discount are symmetric by construction.</p>\n<p><strong>3B. Cherry-pick cheapest deposits</strong></p>\n<p><strong>Attack:</strong> scan the pool for deposits that require the least nominal <code>iCKB</code> to withdraw and then withdraw those deposits first.</p>\n<p><strong>Trace:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L76\"><code>deposit_to_ickb</code></a> computes <code>amount * AR_0 / AR_m</code>. RFC 0023’s <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md#calculation\">maximum-withdrawable-capacity formula</a> scales the later DAO claim by <code>AR_n / AR_m</code>, and the whitepaper’s <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#ickbckb-exchange-rate-calculation\">exchange-rate calculation</a> values the same deposit from block <code>m</code> at <code>100000 CKB * 10 ^ 16 / AR_m</code> <code>iCKB</code>, excluding occupied capacity.</p>\n<p>Deposits with higher <code>AR_m</code> require less nominal <code>iCKB</code> because the formula values them lower in <code>iCKB</code>, not because the pool applies a discount.</p>\n<p><strong>Result:</strong> <strong>No mispricing.</strong> Each deposit is priced by the same formula, up to integer-division rounding.</p>\n<p><strong>3C. Integer rounding exploitation</strong></p>\n<p><strong>Attack:</strong> create many small deposits to accumulate rounding errors.</p>\n<p><strong>Trace:</strong> the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/economic_precision.rs#L5-L92\">rounding mint test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/economic_precision.rs#L93-L227\">rounding withdrawal test</a> show that the reported whole-CKB or rounded claims fail with <code>AmountMismatch</code> unless the exact shannon-precision value is used. The supposed extraction path does not validate on chain.</p>\n<p><strong>Result:</strong> <strong>Blocked by exact shannon-precision accounting.</strong></p>\n<h3><a name=\"p-24105-class-4-data-manipulation-5\" class=\"anchor\" href=\"#p-24105-class-4-data-manipulation-5\" aria-label=\"Heading link\"></a>Class 4: Data Manipulation</h3>\n<p>These cases test whether malformed cells can enter the accounting flow with misleading metadata.</p>\n<p><strong>4A. Receipt with zero deposit_quantity</strong></p>\n<p><strong>Trace:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L114-L116\"><code>entry.rs:114-116</code></a> rejects zero-quantity receipts. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receipt_matching.rs#L5-L41\">zero-quantity receipt test</a> shows the output creation failure directly, so input receipts with zero quantity cannot exist as live cells.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>4B. Receipt amount without matching deposit</strong></p>\n<p><strong>Trace:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L132-L137\"><code>check_output</code></a> uses a <code>BTreeMap</code> keyed by <code>deposit_amount</code>. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receipt_matching.rs#L42-L78\">over-counted receipt test</a> shows that a receipt cannot claim more same-sized deposits than the transaction actually creates, and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receipt_matching.rs#L79-L112\">unmatched receipt-amount test</a> shows that a receipt amount with no matching deposit bucket yields <code>ReceiptMismatch</code>.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>4C. Cell with iCKB Logic lock + non-DAO type</strong></p>\n<p><strong>Trace:</strong> once <code>iCKB Logic</code> executes, <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L72\"><code>celltype.rs:72</code></a> rejects <code>(ScriptType::IckbLogic, _)</code> with <code>ScriptMisuse</code>. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs#L5-L60\">lock-only non-DAO output test</a> shows that such an output can still be created because output locks do not execute at creation time, but spending it later fails with <code>ScriptMisuse</code>.</p>\n<p><strong>Result:</strong> <strong>Cannot be spent successfully.</strong></p>\n<p><strong>4D. NervosDAO withdrawal request classified as deposit</strong></p>\n<p><strong>Trace:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/dao.rs#L17-L22\"><code>is_deposit_data</code></a> checks for exactly 8 zero bytes. Withdrawal requests have non-zero data that stores the block number, so they fall through to <code>ScriptType::Unknown</code> and then <code>CellType::Unknown</code>.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>4E. Deposit capacity manipulation</strong></p>\n<p><strong>Attack:</strong> inflate <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L47-L49\"><code>extract_unused_capacity</code></a> by manipulating cell fields.</p>\n<p><strong>Trace:</strong> CKB requires <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#cell-data\">occupied capacity to fit within cell capacity</a>, and <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L47-L49\"><code>extract_unused_capacity</code></a> subtracts that VM-computed occupied capacity from the actual cell capacity. For the standard iCKB deposit shape, the whitepaper’s <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#ickbckb-exchange-rate-calculation\">exchange-rate calculation</a> uses <code>c_o = 82 CKB</code>. That occupied capacity is fixed by the deposit structure, not chosen independently by the attacker.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>4F. Deposit interest/maturity reset</strong> (<a href=\"https://github.com/ickb/whitepaper/issues/18\">whitepaper#18</a>)</p>\n<p><strong>Attack:</strong> consume an <code>iCKB</code> deposit and create a new deposit at the same output index, effectively resetting the deposit’s age and accrued interest in the pool. This would lower pool-wide returns at minimal cost.</p>\n<p><strong>Trace:</strong> the specific same-index reset described here is blocked by <code>NervosDAO</code> phase 1. The receiptless aggregate-deposit variant is a different claim.</p>\n<ol>\n<li>\n<p><strong>NervosDAO blocks it</strong>: when a DAO deposit is consumed, <a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L337-L389\"><code>validate_withdrawing_cell</code></a> requires the output at the same index to be a withdrawal request with non-zero data containing the deposit block number. A new deposit with 8 zero bytes fails the <a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L382-L385\"><code>stored_block_number != deposit_header.block_number</code></a> check because genesis block number <code>0</code> does not match the real deposit block. The transaction is rejected.</p>\n</li>\n<li>\n<p><strong>By contrast, the broader provenance-blind path is a different claim.</strong> The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L5-L78\">receiptless deposit-admission test</a> shows that <code>ickb_logic</code> later accepts a receiptless DAO-shaped output as a structurally valid deposit input once it exists.</p>\n</li>\n</ol>\n<p>The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L79-L174\">delta-only spread test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L342-L423\">oversized spread test</a> show that the contract accepts a self-funded soft-cap spread, while the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L297-L341\">deposit-alone spread block test</a> blocks the deposit-only variant.</p>\n<p>The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L175-L296\">narrowing comment in the phase-2 claim test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs#L175-L296\">self-funded principal claim test</a> make the limit explicit: the executed path still does not prove receipt-backed-principal theft or duplicated recovery.</p>\n<p>So the specific “same output index” reset is blocked by NervosDAO. The receiptless aggregate-deposit variant stays a self-funded provenance-blind edge case rather than a confirmed double-claim exploit.</p>\n<p><strong>Result:</strong> <strong>Blocked for the same-index reset described here.</strong> The receiptless aggregate-deposit path exists, but the current tests still stop short of proving receipt-backed-principal theft or duplicated recovery.</p>\n<h3><a name=\"p-24105-class-5-cross-script-interactions-6\" class=\"anchor\" href=\"#p-24105-class-5-cross-script-interactions-6\" aria-label=\"Heading link\"></a>Class 5: Cross-Script Interactions</h3>\n<p>These scenarios check whether behavior that is safe in isolation breaks once multiple scripts share a transaction.</p>\n<p><strong>5A. Witness malleability during withdrawal</strong> (<a href=\"https://github.com/ickb/whitepaper/issues/22\">whitepaper#22</a>, credit: <span class=\"mention\">@XuJiandong</span>)</p>\n<p><strong>Attack:</strong> tamper with witness data for the <code>iCKB Logic</code> lock group (unsigned lock). All three witness fields in the group (<code>lock</code>, <code>input_type</code>, <code>output_type</code>) are malleable because <code>iCKB Logic</code> does not use signature-based verification.</p>\n<p><strong>Trace:</strong> <code>iCKB Logic</code> does not read witnesses. <code>NervosDAO</code> does read <code>input_type</code> from the witness to locate the deposit header (<a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L63-L98\"><code>dao.c:63-98</code></a>). If an attacker tampers with that header index, <code>NervosDAO</code> later compares the claimed deposit block number with the actual deposit header and fails at <a href=\"https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L190-L191\"><code>deposited_block_number != deposit_data.block_number</code></a>.</p>\n<p>The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/dao_phase2_batching.rs#L66-L110\">iCKB malformed witness test</a> and the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/melt_pairing_and_witness.rs#L142-L201\">Owned Owner malformed witness test</a> reproduce that malformed header-index witness failure path in <code>iCKB Logic</code> and <code>Owned Owner</code> withdrawal flows.</p>\n<p>The <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#unsigned-lock-witnesses-malleability\">whitepaper’s unsigned-lock-witnesses section</a> already documents that general malleability risk and warns against combining these scripts with witness-dependent logic.</p>\n<p><strong>Result:</strong> <strong>Can cause transaction failure (griefing), cannot cause fund loss.</strong> This is a liveness issue, not a safety issue. <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#unsigned-lock-witnesses-malleability\">Documented in the whitepaper</a>.</p>\n<p><strong>5B. Separate lock/type group execution desync</strong></p>\n<p><strong>Attack:</strong> exploit dual execution in the hope that one run passes while the other fails.</p>\n<p><strong>Trace:</strong> CKB requires ALL script groups to pass (<a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/verify.rs#L197-L213\">the verifier loop</a> returns an error if any <code>verify_script_group(...)</code> call fails). Both lock and type executions see identical cells at absolute indices and perform the same balance checks. If either fails, the transaction is rejected.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>5C. Non-empty-args iCKB Logic variant</strong></p>\n<p><strong>Attack:</strong> create a cell with <code>{iCKB Logic code_hash, Data1, [0x01]}</code> as type, hoping to bypass validation.</p>\n<p><strong>Trace:</strong> different args produce a different script hash, so the cell is not recognized by <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L95-L112\"><code>script_type()</code></a>. Even if it executes as its own type group, it still fails <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L14-L36\"><code>has_empty_args()</code></a>. The non-empty-args poisoning regressions in <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs\">phase2_sibling_classification.rs</a> cover both output-sibling and input-sibling variants.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>5D. Orphaned Owned Owner cell</strong></p>\n<p><strong>Trace:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/owned_owner/src/entry.rs#L57-L60\"><code>owned_owner/entry.rs:57-60</code></a> requires every metapoint to have exactly <code>owned==1, owner==1</code>. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/pair_formation.rs#L260-L289\">orphan-owner rejection test</a> shows that an orphan type-script owner cell is rejected immediately. A separate lock-only orphan case can still be created at output-lock creation time and later strand, as shown by the <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/owned_owner/pair_formation.rs#L179-L259\">orphan withdrawal-request dead-state test</a>.</p>\n<p><strong>Result:</strong> <strong>Blocked when <code>Owned Owner</code> executes.</strong> Lock-only look-alikes can still be created and later fail.</p>\n<p><strong>5E. Limit Order value decrease</strong></p>\n<p><strong>Trace:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L103-L105\"><code>limit_order/entry.rs:103-105</code></a> enforces value conservation with <code>C256</code> (checked <code>U256</code>). Any decrease is rejected.</p>\n<p><strong>Result:</strong> <strong>Blocked.</strong></p>\n<p><strong>5F. Limit Order confusion attack</strong></p>\n<p><strong>Trace:</strong> CKB builds lock groups only from input locks, while type groups come from both input and output types (<a href=\"https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L716-L739\"><code>types.rs:716-739</code></a>). A limit-order cell is the lock-only <code>(true, false)</code> case in <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L48-L56\"><code>limit_order/entry.rs:48-56</code></a>, so an attacker can create phantom order outputs with arbitrary master outpoints without running <code>limit_order</code> at creation time. One manifestation is a fake order that shares a real master outpoint; if a user later melts the wrong order, the real order becomes permanently stranded.</p>\n<p><strong>Result:</strong> <strong>Known vulnerability.</strong> <a href=\"https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#confusion-attack-on-limit-order\">Documented in whitepaper</a>. The <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/limit_order/fake_match_lineage.rs#L63-L122\">real-order stranding test</a> confirms the later real-order stranding path on the deployed binary.</p>\n<p>The whitepaper’s mitigation is front-end lineage checking from the original mint transaction. Under the deployed lock-only design, the chain does not validate phantom orders at creation time because the order cell is created as an output lock-only cell.</p>\n<h3><a name=\"p-24105-class-6-edge-cases-7\" class=\"anchor\" href=\"#p-24105-class-6-edge-cases-7\" aria-label=\"Heading link\"></a>Class 6: Edge Cases</h3>\n<p>The remaining scenarios are boundary checks, platform constraints, or known economic limitations.</p>\n<p><strong>6A. Boundary values</strong></p>\n<p><strong>Trace:</strong> the minimum deposit check uses <code>&lt;</code> (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L101\"><code>entry.rs:101</code></a>), so exactly 1000 CKB is allowed. The maximum uses <code>&gt;</code> (<a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L104\"><code>entry.rs:104</code></a>), so exactly 1M CKB is also allowed. The boundary-value regressions in <a href=\"https://github.com/ickb/contracts/blob/31d593f163fc03ad2936976ccd9cafa514cc7252/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs\">deposit_bounds.rs</a> cover both edges.</p>\n<p><strong>Result:</strong> <strong>Correct.</strong></p>\n<p><strong>6B. u128 overflow in balance equation</strong></p>\n<p><strong>Trace:</strong> <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/Cargo.toml#L6\"><code>overflow-checks = true</code></a> is enabled in <code>scripts/Cargo.toml</code>. Overflow panics and rejects the transaction.</p>\n<p><strong>Result:</strong> <strong>Blocked</strong> (by the compiler setting and practical bounds).</p>\n<p><strong>6C. Division by zero in deposit_to_ickb</strong></p>\n<p><strong>Trace:</strong> the <a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md#calculation\">RFC 0023 accumulated-rate rule</a> sets <code>AR_0 = 10 ^ 16</code> and <code>AR_i = AR_{i-1} + floor(AR_{i-1} * s_i / C_{i-1})</code>, so every deposit header has non-zero <code>AR_m</code>. <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L71-L84\"><code>deposit_to_ickb</code></a> cannot divide by zero.</p>\n<p><strong>Result:</strong> <strong>Impossible.</strong></p>\n<p><strong>6D. <code>extract_unused_capacity</code> underflow</strong></p>\n<p><strong>Trace:</strong> CKB VM enforces <code>capacity &gt;= occupied_capacity</code> for all cells. The subtraction at <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L48\"><code>utils.rs:48</code></a> is safe.</p>\n<p><strong>Result:</strong> <strong>Impossible.</strong></p>\n<p><strong>6E. Chain reorganization between deposit phases</strong> (<a href=\"https://github.com/ickb/whitepaper/issues/15\">whitepaper#15</a>)</p>\n<p><strong>Attack:</strong> deposit phase 1 is included in block B. Before phase 2, a chain reorg removes B. The phase 2 transaction still references B’s header in <code>header_deps</code>, but B no longer exists in the canonical chain.</p>\n<p><strong>Trace:</strong> CKB consensus requires all blocks listed in <code>header_deps</code> to exist in the canonical chain (<a href=\"https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#header-deps\">RFC 0022</a>: “the transaction can only be added to the chain if all the block listed in <code>header_deps</code> are already in the chain (uncles excluded)”). If B is reorged out, then (a) the phase 1 deposit cell no longer exists as a live cell, so it cannot be referenced, and (b) the <code>header_dep</code> pointing to B is invalid. The phase 2 transaction is rejected.</p>\n<p><strong>Result:</strong> <strong>Blocked by CKB consensus rules.</strong> Reorgs cannot create phantom deposits.</p>\n<p><strong>6F. Busywork / pool dilution attack</strong> (<a href=\"https://github.com/ickb/whitepaper/issues/8\">whitepaper#8</a>)</p>\n<p><strong>Attack:</strong> an attacker with large capital repeatedly deposits CKB in standard deposits and then withdraws, cycling through the pool. This shifts the maturity distribution: the remaining deposits are younger, so users must wait longer for a mature deposit.</p>\n<p><strong>Trace:</strong> the attack requires sustained capital commitment. Per the <a href=\"https://github.com/ickb/whitepaper/issues/8\">whitepaper analysis</a>, controlling the first available epoch requires about <code>0.6%</code> of pool capital, while controlling the first 3 days requires about <code>10%</code>. With a <code>0.3%</code> APR per 180 epochs, a user blocked for 1 epoch loses about <code>0.0017%</code> interest.</p>\n<p>The attacker earns nothing because the cycled CKB returns to them, still pays transaction fees, and must lock capital for 180 epochs per cycle. As the pool grows, the capital requirement rises proportionally while the impact per unit of capital falls.</p>\n<p><strong>Result:</strong> <strong>Requires sustained capital and yields less impact as the pool grows.</strong> This is a known limitation, not a vulnerability.</p>\n<p><strong>6G. Same-block receipt and deposit consumption</strong></p>\n<p><strong>Attack:</strong> create a deposit plus receipt in <code>TX1</code>, then consume both in <code>TX2</code> (receipt for phase 2 plus deposit for withdrawal) in the hope that the AR difference yields free <code>iCKB</code>.</p>\n<p><strong>Trace:</strong> both were created in the same block (<code>TX1</code>). <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L54-L61\"><code>extract_accumulated_rate</code></a> returns the same AR for both. Since <code>receipt_value == deposit_value</code>, the balance equation yields <code>0 + receipt_value == out_udt + deposit_value</code> → <code>out_udt = 0</code>. No net <code>iCKB</code> is minted.</p>\n<p><strong>Result:</strong> <strong>No profit.</strong></p>\n<p><strong>6H. Race between receipt creation and deposit withdrawal</strong></p>\n<p><strong>Scenario:</strong> a user creates deposit D plus receipt R in phase 1. Before the user performs phase 2, someone else withdraws D.</p>\n<p><strong>Trace:</strong> R still exists and is valid, and its <code>iCKB</code> value is fixed by the creation-block AR. D being consumed by someone else is expected pool behavior, so the user still converts R to <code>iCKB</code> normally in phase 2.</p>\n<p>The protocol remains balanced because the withdrawer paid <a href=\"https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L71-L84\"><code>deposit_to_ickb(D)</code></a> <code>iCKB</code>, and the receipt holder receives the equivalent <code>receipt_iCKB_value(R)</code>.</p>\n<p><strong>Result:</strong> <strong>Pool accounting stays balanced.</strong></p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24110,
          "post_number": 3,
          "topic_id": 10225,
          "topic_title": "iCKB Contracts Revisited: Old Code, New Audit",
          "topic_slug": "ickb-contracts-revisited-old-code-new-audit",
          "author": "ArthurZhang",
          "created_at": "2026-05-02T01:33:02.680000+00:00",
          "updated_at": "2026-05-02T01:33:02.680000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/ickb-contracts-revisited-old-code-new-audit/10225/3",
          "content_text": "Great update.\nThis appendix is almost exactly the kind of scenario map I would need before turning iCKB into a CellScript maturity benchmark. The attack-class structure, traces, expected results, and links to concrete tests make it much easier.",
          "content_html": "<p>Great update.<br>\nThis appendix is almost exactly the kind of scenario map I would need before turning iCKB into a CellScript maturity benchmark. The attack-class structure, traces, expected results, and links to concrete tests make it much easier.</p>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    },
    {
      "topic_id": 10199,
      "title": "Cellora — designing a production indexing and query service for CKB (feedback welcome)",
      "slug": "cellora-designing-a-production-indexing-and-query-service-for-ckb-feedback-welcome",
      "url": "https://talk.nervos.org/t/cellora-designing-a-production-indexing-and-query-service-for-ckb-feedback-welcome/10199",
      "created_at": "2026-04-22T15:33:26.290000+00:00",
      "last_posted_at": "2026-05-02T01:21:16.135000+00:00",
      "category_id": 32,
      "tags": [
        "CKB",
        "Nervos-项目动态",
        "dapp",
        "testnet"
      ],
      "posters": [
        "Original Poster",
        "Frequent Poster",
        "Frequent Poster",
        "Most Recent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24109,
          "post_number": 8,
          "topic_id": 10199,
          "topic_title": "Cellora — designing a production indexing and query service for CKB (feedback welcome)",
          "topic_slug": "cellora-designing-a-production-indexing-and-query-service-for-ckb-feedback-welcome",
          "author": "phroi",
          "created_at": "2026-05-02T01:21:16.135000+00:00",
          "updated_at": "2026-05-02T01:21:16.135000+00:00",
          "reply_to_post_number": 6,
          "url": "https://talk.nervos.org/t/cellora-designing-a-production-indexing-and-query-service-for-ckb-feedback-welcome/10199/8",
          "content_text": "matt_ckb:\nWithout the Flyclient proof, I have trouble seeing how the client can verify that the block header returned from Cellora has been included in the chain. Am I missing something?\nEven if the returned header is anchored to consensus, there is still the harder question: how does the client prove that no matching cells or txs were omitted from the answer?\nIf the client wants both consensus anchoring and query completeness for itself, it still needs its own light client or full node.\nThe more interesting design space is not “one provider proves everything”, but “independent parties reproducing the same canonical view at the same tip”.\nBeen chiseling away at a design in that direction: not fully trustless, but potentially a useful middle ground for users willing to trade a bit of trust for much less sync time.\nPhroi",
          "content_html": "<aside class=\"quote no-group\" data-username=\"matt_ckb\" data-post=\"6\" data-topic=\"10199\">\n<div class=\"title\">\n<div class=\"quote-controls\"></div>\n<img alt=\"\" width=\"24\" height=\"24\" src=\"https://talk.nervos.org/user_avatar/talk.nervos.org/matt_ckb/48/6296_2.png\" class=\"avatar\"> matt_ckb:</div>\n<blockquote>\n<p>Without the Flyclient proof, I have trouble seeing how the client can verify that the block header returned from Cellora has been included in the chain. Am I missing something?</p>\n</blockquote>\n</aside>\n<p>Even if the returned header is anchored to consensus, there is still the harder question: how does the client prove that no matching cells or txs were omitted from the answer?</p>\n<p>If the client wants both consensus anchoring and query completeness for itself, it still needs its own light client or full node.</p>\n<p>The more interesting design space is not “one provider proves everything”, but “independent parties reproducing the same canonical view at the same tip”.</p>\n<p>Been chiseling away at a design in that direction: not fully trustless, but potentially a useful middle ground for users willing to trade a bit of trust for much less sync time.</p>\n<p>Phroi</p>",
          "like_count": 0,
          "quote_count": 1
        }
      ]
    },
    {
      "topic_id": 10193,
      "title": "CellScript - A DSL for Cell-Based Contracts",
      "slug": "cellscript-a-dsl-for-cell-based-contracts",
      "url": "https://talk.nervos.org/t/cellscript-a-dsl-for-cell-based-contracts/10193",
      "created_at": "2026-04-21T04:43:38.654000+00:00",
      "last_posted_at": "2026-05-02T01:12:37.583000+00:00",
      "category_id": 49,
      "tags": [
        "CKB-VM",
        "CellScript",
        "DSL"
      ],
      "posters": [
        "Original Poster, Most Recent Poster",
        "Frequent Poster",
        "Frequent Poster",
        "Frequent Poster",
        "Frequent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24106,
          "post_number": 18,
          "topic_id": 10193,
          "topic_title": "CellScript - A DSL for Cell-Based Contracts",
          "topic_slug": "cellscript-a-dsl-for-cell-based-contracts",
          "author": "phroi",
          "created_at": "2026-05-02T00:41:47.201000+00:00",
          "updated_at": "2026-05-02T00:41:47.201000+00:00",
          "reply_to_post_number": 17,
          "url": "https://talk.nervos.org/t/cellscript-a-dsl-for-cell-based-contracts/10193/18",
          "content_text": "Hey Arthur, you are very welcome to try iCKB in CellScript\nTo make that easier, I tightened the iCKB artifacts around the relevant DAO, header, witness, and deployment details:\nickb/contracts PR #19: merged. Adds the local executable review plus the expanded scripts/tests suites and replay-heavy cases. See also iCKB Contracts Revisited: Old Code, New Audit\nickb/whitepaper PR #24: merged. Consolidates the protocol and deployment notes.\nnervosnetwork/rfcs PR #453: open. Notes the current DAO same-serialized-lock-size rule that nodes enforce for phase-1 withdrawals.\nSo if you still want to use iCKB as a maturity benchmark, the code and docs should be a much cleaner starting point now.\nHappy to help once you get to concrete fixtures,\nPhroi",
          "content_html": "<p>Hey Arthur, you are very welcome to try iCKB in CellScript <img src=\"https://talk.nervos.org/images/emoji/apple/hugs.png?v=15\" title=\":hugs:\" class=\"emoji\" alt=\":hugs:\" loading=\"lazy\" width=\"20\" height=\"20\"></p>\n<p>To make that easier, I tightened the iCKB artifacts around the relevant DAO, header, witness, and deployment details:</p>\n<ul>\n<li><a href=\"https://github.com/ickb/contracts/pull/19\"><code>ickb/contracts</code> PR #19</a>: merged. Adds the local executable review plus the expanded <code>scripts/tests</code> suites and replay-heavy cases. See also <a href=\"https://talk.nervos.org/t/ickb-contracts-revisited-old-code-new-audit/10225\">iCKB Contracts Revisited: Old Code, New Audit</a></li>\n<li><a href=\"https://github.com/ickb/whitepaper/pull/24\"><code>ickb/whitepaper</code> PR #24</a>: merged. Consolidates the protocol and deployment notes.</li>\n<li><a href=\"https://github.com/nervosnetwork/rfcs/pull/453\"><code>nervosnetwork/rfcs</code> PR #453</a>: open. Notes the current DAO same-serialized-lock-size rule that nodes enforce for phase-1 withdrawals.</li>\n</ul>\n<p>So if you still want to use iCKB as a maturity benchmark, the code and docs should be a much cleaner starting point now.</p>\n<p>Happy to help once you get to concrete fixtures,<br>\nPhroi</p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24108,
          "post_number": 19,
          "topic_id": 10193,
          "topic_title": "CellScript - A DSL for Cell-Based Contracts",
          "topic_slug": "cellscript-a-dsl-for-cell-based-contracts",
          "author": "ArthurZhang",
          "created_at": "2026-05-02T01:12:37.583000+00:00",
          "updated_at": "2026-05-02T01:12:37.583000+00:00",
          "reply_to_post_number": 18,
          "url": "https://talk.nervos.org/t/cellscript-a-dsl-for-cell-based-contracts/10193/19",
          "content_text": "Hi Phroi,\nThat is very helpful.\nI will read through these updates before turning this into concrete fixtures.\nOnce I have the first small fixture set ready, I will tag you again for feedback.\nReally appreciate the help.",
          "content_html": "<p>Hi Phroi,</p>\n<p>That is very helpful. <img src=\"https://talk.nervos.org/images/emoji/apple/100.png?v=15\" title=\":100:\" class=\"emoji\" alt=\":100:\" loading=\"lazy\" width=\"20\" height=\"20\"><br>\nI will read through these updates before turning this into concrete fixtures.<br>\nOnce I have the first small fixture set ready, I will tag you again for feedback.<br>\nReally appreciate the help.</p>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    },
    {
      "topic_id": 8369,
      "title": "[DIS] iCKB & dCKB Rescuer Funding Proposal (Non-Coding Expenses)",
      "slug": "dis-ickb-dckb-rescuer-funding-proposal-non-coding-expenses",
      "url": "https://talk.nervos.org/t/dis-ickb-dckb-rescuer-funding-proposal-non-coding-expenses/8369",
      "created_at": "2024-10-18T14:39:31.343000+00:00",
      "last_posted_at": "2026-05-02T00:45:39.136000+00:00",
      "category_id": 65,
      "tags": [],
      "posters": [
        "Original Poster, Most Recent Poster",
        "Frequent Poster",
        "Frequent Poster",
        "Frequent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24107,
          "post_number": 28,
          "topic_id": 8369,
          "topic_title": "[DIS] iCKB & dCKB Rescuer Funding Proposal (Non-Coding Expenses)",
          "topic_slug": "dis-ickb-dckb-rescuer-funding-proposal-non-coding-expenses",
          "author": "phroi",
          "created_at": "2026-05-02T00:45:39.136000+00:00",
          "updated_at": "2026-05-02T00:45:39.136000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/dis-ickb-dckb-rescuer-funding-proposal-non-coding-expenses/8369/28",
          "content_text": "Hey all, small update on the iCKB side\nI cleaned up a few iCKB artifacts around the DAO, headers, witnesses, and deployment notes:\nickb/contracts PR #19: merged. Adds the local executable review plus the expanded scripts/tests suites and replay-heavy cases. See also iCKB Contracts Revisited: Old Code, New Audit\nickb/whitepaper PR #24: merged. Consolidates the protocol and deployment notes.\nnervosnetwork/rfcs PR #453: open. Notes the current DAO same-serialized-lock-size rule that nodes enforce for phase-1 withdrawals.\nThat last point is the same current node rule I mentioned earlier here for dCKB Rescuer, so at least that constraint is now written down more clearly.\nLove & Peace, Phroi",
          "content_html": "<p>Hey all, small update on the iCKB side <img src=\"https://talk.nervos.org/images/emoji/apple/hugs.png?v=15\" title=\":hugs:\" class=\"emoji\" alt=\":hugs:\" loading=\"lazy\" width=\"20\" height=\"20\"></p>\n<p>I cleaned up a few iCKB artifacts around the DAO, headers, witnesses, and deployment notes:</p>\n<ul>\n<li>\n<p><a href=\"https://github.com/ickb/contracts/pull/19\"><code>ickb/contracts</code> PR #19</a>: merged. Adds the local executable review plus the expanded <code>scripts/tests</code> suites and replay-heavy cases. See also <a href=\"https://talk.nervos.org/t/ickb-contracts-revisited-old-code-new-audit/10225\">iCKB Contracts Revisited: Old Code, New Audit</a></p>\n</li>\n<li>\n<p><a href=\"https://github.com/ickb/whitepaper/pull/24\"><code>ickb/whitepaper</code> PR #24</a>: merged. Consolidates the protocol and deployment notes.</p>\n</li>\n<li>\n<p><a href=\"https://github.com/nervosnetwork/rfcs/pull/453\"><code>nervosnetwork/rfcs</code> PR #453</a>: open. Notes the current DAO same-serialized-lock-size rule that nodes enforce for phase-1 withdrawals.</p>\n</li>\n</ul>\n<p>That last point is the same current node rule I mentioned earlier here for dCKB Rescuer, so at least that constraint is now written down more clearly.</p>\n<p>Love &amp; Peace, Phroi</p>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    },
    {
      "topic_id": 10221,
      "title": "Revamping and Refactoring the CKB Wallet Connection Experience: A Modular Compound Component for React Developers",
      "slug": "revamping-and-refactoring-the-ckb-wallet-connection-experience-a-modular-compound-component-for-react-developers",
      "url": "https://talk.nervos.org/t/revamping-and-refactoring-the-ckb-wallet-connection-experience-a-modular-compound-component-for-react-developers/10221",
      "created_at": "2026-04-30T19:28:31.062000+00:00",
      "last_posted_at": "2026-05-01T19:35:13.576000+00:00",
      "category_id": 49,
      "tags": [
        "CKB",
        "wallet"
      ],
      "posters": [
        "Original Poster",
        "Most Recent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24103,
          "post_number": 2,
          "topic_id": 10221,
          "topic_title": "Revamping and Refactoring the CKB Wallet Connection Experience: A Modular Compound Component for React Developers",
          "topic_slug": "revamping-and-refactoring-the-ckb-wallet-connection-experience-a-modular-compound-component-for-react-developers",
          "author": "Ajay",
          "created_at": "2026-05-01T19:35:13.576000+00:00",
          "updated_at": "2026-05-01T19:35:13.576000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/revamping-and-refactoring-the-ckb-wallet-connection-experience-a-modular-compound-component-for-react-developers/10221/2",
          "content_text": "This is awesome",
          "content_html": "<p>This is awesome</p>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    }
  ]
}