<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Nervos Blog</title>
        <link>https://docs.nervos.org/blog</link>
        <description>Blog Posts About Nervos Blockchain</description>
        <lastBuildDate>Fri, 05 Jul 2019 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Introduction to CKB Script Programming 1: Validation Model]]></title>
            <link>https://docs.nervos.org/blog/intro-to-ckb-script-programming-1</link>
            <guid>https://docs.nervos.org/blog/intro-to-ckb-script-programming-1</guid>
            <pubDate>Fri, 05 Jul 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[As of now, the cell validation model in CKB has been more or less stablized, hence I'm starting a series of article introducing CKB script programming here. My goal here is to fill in all the missing implementation details one need to write CKB scripts after reading the whitepaper, so you can start exploring this beautiful wonderland CKB presents.]]></description>
            <content:encoded><![CDATA[<p>As of now, the cell validation model in CKB has been more or less stablized, hence I'm starting a series of article introducing CKB script programming here. My goal here is to fill in all the missing implementation details one need to write CKB scripts after reading the whitepaper, so you can start exploring this beautiful wonderland CKB presents.</p>
<p>You might noticed that I call the code running on CKB as <code>script</code>, not <code>smart contract</code>. This is because smart contract is quite a confusing term to me, and I want to use a different word here to indicate CKB's unique programmability. A script in CKB's sense need not be just a script we see in scripting languages such as Ruby, JS, it actually refers to the RISC-V format binary you run on CKB VM.</p>
<p>This first post here, is dedicated to the brand <a href="https://github.com/nervosnetwork/ckb/pull/913" target="_blank" rel="noopener noreferrer">new verification model</a> introduced in CKB v0.14.0. It might sound boring but I promise you this is the last post without actual examples to play with <!-- -->:P</p>
<p>Note even though I believe CKB's programming model is quite stable now, development is still happening so there might be changes. I will try my best to make sure this post is updated but if anything confuses you, this post is describing CKB's Lina mainnet version now.</p>
<p>Below illustrates a real transaction on CKB:</p>
<p align="center"></p><p><img decoding="async" loading="lazy" alt="Transaction Example" src="https://docs.nervos.org/assets/images/tx-265196715323e0d2284c5c536f9df20d.svg" class="img_ev3q"></p><p></p>
<p>There are a lot of things going on in this graph, and we will come back to this graph again in later posts. Today, we will just focus on 2 entities in the cell data structure: <code>lock</code> and <code>type</code>.</p>
<div class="language-rust codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-rust codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">struct</span><span class="token plain"> </span><span class="token type-definition class-name" style="color:rgb(78, 201, 176)">CellOutput</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> capacity</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Capacity</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> lock</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Script</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token attribute attr-name" style="color:var(--code-function)">#[serde(rename = </span><span class="token attribute attr-name string" style="color:rgb(206, 145, 120)">"type"</span><span class="token attribute attr-name" style="color:var(--code-function)">)]</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> type_</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">Option</span><span class="token operator" style="color:var(--text-secondary)">&lt;</span><span class="token class-name" style="color:rgb(78, 201, 176)">Script</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>From the data structure we can see that <code>lock</code> and <code>type</code> shared the same structure, later we can show that they are also executed in the same environment, the differences between them are just in a few tiny bits:</p>
<ul>
<li><code>lock</code> is required, while <code>type</code> is optional</li>
<li>Mentally, they are used to capture different use cases.</li>
</ul>
<p>We will first start with <code>type</code> script here.</p>
<h1>Type Script</h1>
<p>Note the name here is just a lucky accident, it is not related to the beloved <a href="https://www.typescriptlang.org/" target="_blank" rel="noopener noreferrer">programming language</a>.</p>
<p>If you think about it, a transaction on CKB(or most UTXO-based blockchains) just transforms one set of cells(or UTXOs) to another set of cells. What's interesting, is the actual transformation here. That's where we start to design CKB's verification model: how can we build a model to better validate the cell transformations?</p>
<p>That's where a <code>type</code> script comes in play: a type script is used to validate certain rules in the cell transformation phase. Some examples here include:</p>
<ul>
<li>Validating UDT(user defined token) balances to ensure no new token is invalidly issued.</li>
<li>Ensuring a unique name is assigned to a cell that might be mutated. Note this is a fun one, please expect a future article dedicated entirely to this topic.</li>
<li>Implementing economic constructs. In fact NervosDAO is completely implemented as a <a href="https://github.com/nervosnetwork/ckb-system-scripts/blob/66d7da8ec72dffaa7e9c55904833951eca2422a9/c/dao.c" target="_blank" rel="noopener noreferrer">type script</a> with minimal support from the consensus layer.</li>
<li>A bitcoin VM can be compiled to RISC-V binary, which can transform CKB into an alternative bitcoin implementation :)</li>
<li>Keep in mind that in addition to data, cell can be used to store code as well, hence a type script can also be used to run tests on the code in cell to ensure certain behavior.</li>
</ul>
<p>In a nutshell, type script can be used to capture any validation logic you need in the cell transformation. Combined with CKB's flexible virtual machine, I believe this will provide endless potentials.</p>
<h1>Lock Script</h1>
<p>Type script captures the cell transformation logic, but there's still one thing missing from the picture: how can I guard my own cell from someone else? In other words, how can I ensure my tokens stay mine in an ever-changing world?</p>
<p>This is why we designed the always required lock script. A cell can only be consumed when the lock script can be executed sucessfully. This is different from type script, which might be totally optional. A lock script is always there to guard the security of a cell.</p>
<p>Typically, you would expect that a lock script contains a signature verification phase, like all the other blockchains do, but there are also brand new use cases unlocked by CKB:</p>
<ul>
<li>The actual signature algorithm is totally determined by the lock script, and you are free to use any lock script. That means you are free to incorporate any signature algorithms that suit your need. In the official CKB distribution we are including <a href="https://github.com/nervosnetwork/ckb-system-scripts/blob/66d7da8ec72dffaa7e9c55904833951eca2422a9/c/secp256k1_blake160_sighash_all.c" target="_blank" rel="noopener noreferrer">secp256k1 algorithm</a> as the default lock script. But you don't have to use this, if someone implements a lock script using schnorr signature, you are more than welcome to use that one.</li>
<li>In addition to signature verification, a lock script can also include other rules to unlock the cell as well. For example, I can configure my lock script to pass if the transaction contains an output cell that uses my lock script, but has more capacity than my consumed cell. This way when someone sends me capacity, they can consume my existing cell and create a new cell for me. They don't have to create a new cell for me like bitcoin requires.</li>
</ul>
<p>In my personal opinion, the best part of CKB, is that a lock script created by the community is treated exactly the same way as the official default one. No priviledge is granted to the official scripts. Unlike some other blockchains, CKB provides the freedom to develop CKB scripts back to the whole community.</p>
<h1>Execution Model</h1>
<p>Now let's see when lock and type scripts are executed.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="back-to-the-example">Back to the Example<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-1#back-to-the-example" class="hash-link" aria-label="Direct link to Back to the Example" title="Direct link to Back to the Example">​</a></h2>
<p>Here's the transaction we see earlier again:</p>
<p align="center"></p><p><img decoding="async" loading="lazy" alt="Transaction Example" src="https://docs.nervos.org/assets/images/tx-265196715323e0d2284c5c536f9df20d.svg" class="img_ev3q"></p><p></p>
<p>For this example, the execution flow is as follows:</p>
<ol>
<li><code>Lock Script 1</code> is executed once.</li>
<li><code>Lock Script 2</code> is executed once.</li>
<li><code>Type Script 1</code> is executed once.</li>
<li><code>Type Script 2</code> is executed once.</li>
</ol>
<p>In later posts we can see both lock and type scripts are executed in the same environment, and both have access to the whole transaction. If any of the script fails, the whole transaction fails. Only when all the scripts succeed, the transaction is considered validated.</p>
<p>There're couple of points worth mentioning:</p>
<ul>
<li>Even though there are 2 input cells with <code>Lock Script 1</code>, it is only executed once, it's up to the actual lock script to locate all the input cells with the same lock script and validate both signature.</li>
<li>Only lock scripts in input cells are executed in this transaction, for example, <code>Lock Script 3</code> is not executed here.</li>
<li>Even though an input cell and an output cell both contain <code>Type Script 1</code>, it is only executed once.</li>
<li>Type scripts in both input and output cells are executed, which include <code>Type Script 1</code> and <code>Type Script 2</code>.</li>
<li>Some cells do not have type scripts, in this case we just omit the execution.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="rules">Rules<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-1#rules" class="hash-link" aria-label="Direct link to Rules" title="Direct link to Rules">​</a></h2>
<p>Now to summary the rules:</p>
<ul>
<li>Lock scripts in input cells are collected and deduped, each unique lock script is executed and only executed once.</li>
<li>Type scripts in input and output cells(if existed) are collected together and deduped, each unique type script is executed and only executed once.</li>
<li>If any script fails, the whole transaction validation fails.</li>
</ul>
<h1>What's Next</h1>
<p>Now that cell model is covered, we will look at how to actual write a CKB VM script in the next post. The default secp256k1 lock script will be examined to show the life of a CKB VM script.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduction to CKB Script Programming 2: Script Basics]]></title>
            <link>https://docs.nervos.org/blog/intro-to-ckb-script-programming-2</link>
            <guid>https://docs.nervos.org/blog/intro-to-ckb-script-programming-2</guid>
            <pubDate>Sat, 13 Jul 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Last post introduced current CKB's validation model. This post will get more fun, since we will show how to deploy script codes to CKB for real. I'm hoping after this post, you should be able to explore the CKB world and work on new script codes as you wish.]]></description>
            <content:encoded><![CDATA[<p>Last post introduced current CKB's validation model. This post will get more fun, since we will show how to deploy script codes to CKB for real. I'm hoping after this post, you should be able to explore the CKB world and work on new script codes as you wish.</p>
<p>This post is written based on current CKB Lina mainnet version now.</p>
<p>A warning here: this will be a long post, since I want to fill in enough for the more interesting topic next week. So you don't have to finish it at once if you don't have enough time. I've tried to split it into individual sections, so you can try each one at a time.</p>
<p>Before we continue, let's distinguish between 2 terms: script, and script code.</p>
<p>In this post and hopefully the whole series, we will distinguish between script, and script code. Script code actually refers to the program you write and compile to use on CKB. Script, on the other hand, actually refers to the script data structure used in CKB, which is a little more than just the script code:</p>
<div class="language-rust codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-rust codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">struct</span><span class="token plain"> </span><span class="token type-definition class-name" style="color:rgb(78, 201, 176)">Script</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> code_hash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token constant" style="color:var(--code-constant)">H256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> hash_type</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">ScriptHashType</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">JsonBytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We can ignore <code>hash_type</code> for now, a future post will explain what it is and it's interesting usage. Later in this post, we will show that <code>code_hash</code> actually just identifies a script code, so for now we can just think of it as script code. What script also includes, is the <code>args</code> part, which distinguishes script from script code. <code>args</code> can be used here to provide additional arguments for a CKB script, for example, while people might all be using the same default lock script code, each of them might have their own pubkey hash, <code>args</code> is exact the place to hold pubkey hash. This way each user of CKB can have different lock script, while sharing the same lock script code.</p>
<p>Note that in most cases, script and script code can be used interchangably, but if you are confused at some places, it might be worthwhile to think of the difference between the 2.</p>
<h1>A Minimal CKB Script Code</h1>
<p>As you might have already heard, CKB is based on the open source RISC-V ISA. But what does that even mean? In my words, it means we are (sort of) embedding a real mini computer in CKB, instead of a virtual machine. The benefit of a real computer, is that you can write any logic you want in any language you want. The first few examples we show here will be written in C for simplicity(well I mean simplicity in the toolchain, not the <a href="http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html" target="_blank" rel="noopener noreferrer">language</a>), but later we will switch to JavaScript based script code, and hopefully show more languages in the series. On CKB there's endless possibilities.</p>
<p>As we mentioned about, CKB VM is more like a real mini computer. CKB script code also looks like a normal Unix style executable program we run on a computer:</p>
<div class="language-c codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-c codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token keyword" style="color:var(--code-keyword)">int</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">main</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:var(--code-keyword)">int</span><span class="token plain"> argc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">char</span><span class="token operator" style="color:var(--text-secondary)">*</span><span class="token plain"> argv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>When compiled via a C compiler, this will become a script code that is runnable on CKB. In other words, CKB just take plain old Unix style executables(but in RISC-V architecture instead of the popular x86 architecture), and run it in a virtual machine environment. If the program returns with 0 as the return code, we consider the script succeeds, all non-zero return codes will be considered script faliures.</p>
<p>In the example above, we are showing a script code that always succeeds, since the return code will always be zero. Please don't use this as your lock script code, otherwise your token can be taken away by anyone.</p>
<p>But the example above won't be interesting, here we will start with an interesting idea: personally I dislike carrot. I do know that carrot is great from a nutritional point of view, but I still want to avoid it due to the taste. Now what if I want to set a rule, that none of my cells on CKB has data that begin with <code>carrot</code>? Let's write a script code to ensure this.</p>
<p>In order to ensure none of the cells can have <code>carrot</code> in cell data, we need a way to first read cell data in the script. CKB provides <code>syscalls</code> to help with this.</p>
<p>To ensure the security of CKB script, each script has to run in an isolated environment that is totally separated from the main computer you are running CKB. This way it won't be able to access data it doesn't need, such as your private keys or passwords. However, for a script to be useful, there must be certain data it want to access, such as the cell a script guards, or a transaction a script validates. CKB provides <code>syscalls</code> to ensure this, syscalls are defined in RISC-V standard, they provide a way to access certain resources provided by the environment. In a normal situation, the environment here means the operating system, but in the case of CKB VM, the environment refers to the actual CKB process. With syscalls, a CKB script can access the whole transaction containing itself, including inputs, outputs, witnesses, and deps.</p>
<p>The good news, is that we have encapsulated syscalls in an easy to use <a href="https://github.com/nervosnetwork/ckb-system-scripts/blob/a7b7c75662ed950c9bd024e15f83ce702a54996e/c/ckb_syscalls.h" target="_blank" rel="noopener noreferrer">header file</a>, you are very welcome to poke around this file to see how syscalls are implemented. The bottomline is you can just grab this header file and use the wrapped functions to make syscalls as you want.</p>
<p>Now with the syscalls at hand, we can start with our carrot-forbidden script:</p>
<div class="language-c codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-c codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:var(--code-keyword)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">&lt;memory.h&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:var(--code-keyword)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">"ckb_syscalls.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token keyword" style="color:var(--code-keyword)">int</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">main</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:var(--code-keyword)">int</span><span class="token plain"> argc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">char</span><span class="token operator" style="color:var(--text-secondary)">*</span><span class="token plain"> argv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">int</span><span class="token plain"> ret</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token class-name" style="color:rgb(78, 201, 176)">size_t</span><span class="token plain"> index </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token class-name" style="color:rgb(78, 201, 176)">uint64_t</span><span class="token plain"> len </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:var(--code-comment)">/* (1) */</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">unsigned</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">char</span><span class="token plain"> buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">6</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">while</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    len </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">6</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token function" style="color:var(--code-function)">memset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">6</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ret </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">ckb_load_cell_data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">&amp;</span><span class="token plain">len</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> index</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> CKB_SOURCE_OUTPUT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:var(--code-comment)">/* (2) */</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ret </span><span class="token operator" style="color:var(--text-secondary)">==</span><span class="token plain"> CKB_INDEX_OUT_OF_BOUND</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain">               </span><span class="token comment" style="color:var(--code-comment)">/* (3) */</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      </span><span class="token keyword" style="color:var(--code-keyword)">break</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:var(--code-function)">memcmp</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"carrot"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">6</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">==</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    index</span><span class="token operator" style="color:var(--text-secondary)">++</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Several points worth explaining here:</p>
<ol>
<li>We will use <code>len</code> field both as an input and output parameter, hence it is passed as a pointer here.</li>
<li>When making a syscall, we need to provide the following: a buffer to hold the data provided by the syscall; a <code>len</code> field denoting both the buffer length, and available data length returned by the syscall; an offset into the input data buffer, and several parameters denoting the exact field we are fetching in the transaction. For more details, please refer to our <a href="https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0009-vm-syscalls/0009-vm-syscalls.md" target="_blank" rel="noopener noreferrer">RFC</a>.</li>
<li>For maximum flexibility, CKB uses the return value of the syscall to represent data fetching status: 0(or <code>CKB_SUCCESS</code>) means success, 1(or <code>CKB_INDEX_OUT_OF_BOUND</code>) means you have finished fetching all indices in a kind, 2(or <code>CKB_ITEM_MISSING</code>) means an entity is not present, such as fetching a type script from a cell that doesn't have one.</li>
</ol>
<p>So to recap, this script would loop through all output cells in the transaction, load the first 6 bytes of each cell data and test if those bytes match <code>carrot</code>. If we found a match, the script would return <code>-1</code>, denoting an error status, if no match is found, the script exits with <code>0</code>, meaning execution success.</p>
<p>To perform the loop, the script would keep an <code>index</code> variable, in each loop iteration, it would tries to make the syscall to fetch the cell denoted by current <code>index</code> value, if the syscall returns <code>CKB_INDEX_OUT_OF_BOUND</code>, it means the script has iterated through all the cells, hence it just exits the loop, otherwise, the loop would continue, the cell data is tested, then <code>index</code> variable is incremented for the next iteration.</p>
<p>This concludes your first useful CKB script code! In the next section, we will see how we can deploy it to CKB and run it.</p>
<h1>Deploying a Script to CKB</h1>
<p>First, we need to compile the carrot source code written above. Since GCC already has upstream RISC-V support, you can of course use the official GCC to build your script code. Or you can use the <a href="https://hub.docker.com/r/nervos/ckb-riscv-gnu-toolchain" target="_blank" rel="noopener noreferrer">docker image</a> we have prepared to save the trouble of compiling GCC:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">ls</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">carrot.c  ckb_consts.h  ckb_syscalls.h</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">sudo</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--rm</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-it</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-v</span><span class="token plain"> </span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token variable builtin class-name" style="color:rgb(78, 201, 176)">pwd</span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token plain">:/code nervos/ckb-riscv-gnu-toolchain:xenial </span><span class="token function" style="color:var(--code-function)">bash</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@dc2c0c209dcd:/</span><span class="token comment" style="color:var(--code-comment)"># cd /code</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@dc2c0c209dcd:/code</span><span class="token comment" style="color:var(--code-comment)"># riscv64-unknown-elf-gcc -Os carrot.c -o carrot</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@dc2c0c209dcd:/code</span><span class="token comment" style="color:var(--code-comment)"># exit</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">exit</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">ls</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">carrot*  carrot.c  ckb_consts.h  ckb_syscalls.h</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>And that's it, CKB can use the compiled executable from GCC directly as scripts on chain, there's no way for further processing. We can now deploy it on chain. Note that I will use CKB's Node.js SDK <a href="https://github.com/ckb-js/lumos" target="_blank" rel="noopener noreferrer">Lumos</a>. Please refer to the official <a href="https://lumos-website.vercel.app/" target="_blank" rel="noopener noreferrer">Docs</a> for how to set it up. Across the serial posts, there are some common codes to set up in the Repl environment with Lumos packages, we won't repeat these codes for simplicity, but you can take the following as a reference:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ node</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token maybe-class-name">Welcome</span><span class="token plain"> to </span><span class="token maybe-class-name">Node</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">js</span><span class="token plain"> v20</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token number" style="color:rgb(181, 206, 168)">12.0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token property-access maybe-class-name">Type</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">".help"</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">for</span><span class="token plain"> more information</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> lumos </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">require</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"@ckb-lumos/lumos"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> indexer </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">lumos</span><span class="token class-name punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token class-name" style="color:rgb(78, 201, 176)">Indexer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"https://testnet.ckb.dev/rpc"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> rpc </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">lumos</span><span class="token class-name punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token class-name" style="color:rgb(78, 201, 176)">RPC</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"https://testnet.ckb.dev/rpc"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">config</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">initializeConfig</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">config</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token constant" style="color:var(--code-constant)">TESTNET</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> wallet </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">address</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token string" style="color:rgb(206, 145, 120)">"ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqvwg2cen8extgq8s5puft8vf40px3f599cytcyd8"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">privkey</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x6109170b275a09ad54877b82f7d9930f88cab5717d484fb4741ae9d1dd078cd6"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> wallet2 </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">address</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2prryvze6fhufxkgjx35psh7w70k3hz7c3mtl4d"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">privkey</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0xace08599f3174f4376ae51fdc30950d4f2d731440382bb0aa1b6b0bd3a9728cd"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>To deploy the script to CKB, we can just create a new cell, with the script code as cell data part:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> fs </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">require</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"fs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> data </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> fs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">readFileSync</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"carrot"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">byteLength</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token number" style="color:rgb(181, 206, 168)">7744</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">transfer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"8000"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"00000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">data</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> carrotTxHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Here I simply create a new cell with enough capacity by sending tokens to another wallet. Now we can create the type script containing the carrot script code:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> bytes </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">require</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"@ckb-lumos/lumos/codec"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">bytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> carrotDataHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">utils</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">ckbHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">bytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">bytify</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> carrotTypeScript </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">codeHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> carrotDataHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">hashType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"data"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">args</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Recall the Script data structure:</p>
<div class="language-rust codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-rust codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">struct</span><span class="token plain"> </span><span class="token type-definition class-name" style="color:rgb(78, 201, 176)">Script</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> code_hash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token constant" style="color:var(--code-constant)">H256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> hash_type</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">ScriptHashType</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">pub</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">JsonBytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We can see that instead of embedding the script code directly in the script data structure, we are only including the code hash, which is a Blake2b hash of the actual script binary code. Since carrot script doesn't use an argument, we can use empty bytes for <code>args</code> part.</p>
<p>Note I'm still ignoring <code>hash_type</code> here, we will leave to a future post to see a different way of specifying code hash. For now, let's keep it simple here.</p>
<p>To run the carrot script, we need to create a new transaction, and set carrot type script as the type script of one of the output cells:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">transfer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token string" style="color:rgb(206, 145, 120)">"100"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"00000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">cellOutput</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">type</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> carrotTypeScript</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>There's one more step needed: in order for CKB to locate the carrot script, we need to reference the cell containing carrot script in one of transaction deps:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">addCellDep</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">outPoint</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">txHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> carrotTxHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">index</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">depType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"code"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now we are ready to sign and send the transaction:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token number" style="color:rgb(181, 206, 168)">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> txHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txHash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token number" style="color:rgb(181, 206, 168)">0xd7b0fea7c1527cde27cc4e7a2e055e494690a384db14cc35cd2e51ec6f078163</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Since this transaction does not have any cell containing <code>carrot</code> in the cell data, the type script validates successfully. Now let's try a different transaction that does have a cell that begins with <code>carrot</code>:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">transfer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain">wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token string" style="color:rgb(206, 145, 120)">"400"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"00000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">cellOutput</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">type</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> carrotTypeScript</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">data</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token maybe-class-name">Buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword module" style="color:var(--code-keyword)">from</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"carrot123"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"utf8"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">addCellDep</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">outPoint</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">txHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> carrotTxHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">index</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x0"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">depType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"code"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token number" style="color:rgb(181, 206, 168)">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token literal-property property">Uncaught</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token maybe-class-name">ResponseException</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token known-class-name class-name" style="color:rgb(78, 201, 176)">Error</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token string-property property">"code"</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">302</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token string-property property">"message"</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token string" style="color:rgb(206, 145, 120)">"TransactionFailedToVerify: Verification failed Script(TransactionScriptError { source: Outputs[0].Type, cause: ValidationFailure: see error code -1 on page.."</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We can see our carrot script rejects a transaction that generates a cell with carrot. Now I can use this script to make sure all my cells are free from carrots!</p>
<p>So to recap, to deploy and run a script as type script, what we need to do is:</p>
<ol>
<li>Compile the script to RISC-V executable binary</li>
<li>Deploy the binary in a cell's data part</li>
<li>Create a type script data structure with the blake2b hash of the binary as <code>code hash</code>, any required arguments of the script code in the <code>args</code> part</li>
<li>Create a new transaction with the type script set in one of the generated cells</li>
<li>Include the outpoint to the cell containing the script code as one of the transaction deps</li>
</ol>
<p>That's really all you need! If your script has run into problems, those are the points you need to check.</p>
<p>Although we only talk about type scripts here, lock script works exactly the same way. The only quirk you need to keep in mind, is that when you create a cell with a specificed lock script, the lock script won't run here. It only runs when you are consuming the cell. So while type script can be used to create the logic that runs when you create the cell, lock script is used to create the logic that runs when you consume the cell. Given this consideration, please make sure your lock script is correct, otherwise you might be losing the tokens in the following scenarios:</p>
<ul>
<li>Your lock script has a bug that someone else can unlock your cell.</li>
<li>Your lock script has a bug that no one(including you) can unlock your cell.</li>
</ul>
<p>One tip we can provide here, is always test your script as a type script attached to an output cell in your transaction, this way when error happens, you will know immediately, your tokens can stay safe.</p>
<h1>Introducing Duktape</h1>
<p>I'm sure you feel the same way as I do now: it's good we can write contracts in C, but C always feels a bit tedious and, let's face it, dangerous. Is there a better way?</p>
<p>Yes of course! We mentioned above CKB VM is essentially a mini computer, and there are tons of solutions we can explore. One thing we have prepared here, is that we can write CKB script codes in JavaScript. Yes you got it right, plain ES5(yes I know, but this is just one example, and you can use a transpiler) JavaScript.</p>
<p>How this is possible? Since we have C compiler available, all we did is just take a JavaScript implementation for the embeded system, in our case, <a href="https://duktape.org/" target="_blank" rel="noopener noreferrer">duktape</a>, compile it from C to RISC-V binary, put it on chain, then boom, we can run JavaScript in CKB! Since we are working with a real mini computer here, there's no stopping us from embeding another VM as CKB script to CKB VM, and exploring this VM on top of VM path.</p>
<p>And we can actually expand from this path, we can have JavaScript on CKB via duktape, we can also have Ruby on CKB via <a href="https://github.com/mruby/mruby" target="_blank" rel="noopener noreferrer">mruby</a>, we can even have Bitcoin Script or EVM on chain if we just compile their VM and put it on chain. This ensures CKB VM can both help us preserve legacy and build a diversified ecosystem. All languages should be and are treated equal on CKB, the freedom should be in the hands of blockchain contract developers.</p>
<p>At this stage you might want to ask: yes this is possible, but won't VM on top of VM be slow? I believe it really depends on your use case to say if this is gonna be slow. I'm a firm believer that benchmarks make no sense unless we put it in a real use case with standard hardware requirements. So wait to see if this is really gonna be an issue. In my opinion, higher languages are more likely to be used in type scripts to guard cell transformation, in this case, I doubt it's gonna be slow. Besides, we are also working on this field to optimize both CKB VM and the VMs on top of CKB VM to make it faster and faster <!-- -->:P</p>
<p>To use duktape on CKB, first you need to compile duktape itself into a RISC-V executable binary:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">git</span><span class="token plain"> clone https://github.com/xxuejie/ckb-duktape.git</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">cd</span><span class="token plain"> ckb-duktape</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">git</span><span class="token plain"> submodule init</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">git</span><span class="token plain"> submodule update</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">sudo</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--rm</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-it</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-v</span><span class="token plain"> </span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token variable builtin class-name" style="color:rgb(78, 201, 176)">pwd</span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token plain">:/code nervos/ckb-riscv-gnu-toolchain:xenial </span><span class="token function" style="color:var(--code-function)">bash</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@0d31cad7a539:~</span><span class="token comment" style="color:var(--code-comment)"># cd /code</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@0d31cad7a539:/code</span><span class="token comment" style="color:var(--code-comment)"># make</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Os</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-DCKB_NO_MMU</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_soft_float</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_float_abi_soft</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Iduktape</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ic</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ischema</span><span class="token plain"> -Ideps/ckb-c-stdlib -Ideps/ckb-c-stdlib/molecule </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Wall</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Werror</span><span class="token plain"> c/entry.c </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-c</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/entry.o</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Os</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-DCKB_NO_MMU</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_soft_float</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_float_abi_soft</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Iduktape</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ic</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ischema</span><span class="token plain"> -Ideps/ckb-c-stdlib -Ideps/ckb-c-stdlib/molecule </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Wall</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Werror</span><span class="token plain"> duktape/duktape.c </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-c</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/duktape.o</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc build/entry.o build/duktape.o </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/duktape </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-lm</span><span class="token plain"> -Wl,-static -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-s</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Os</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-DCKB_NO_MMU</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_soft_float</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_float_abi_soft</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Iduktape</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ic</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ischema</span><span class="token plain"> -Ideps/ckb-c-stdlib -Ideps/ckb-c-stdlib/molecule </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Wall</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Werror</span><span class="token plain"> c/repl.c </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-c</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/repl.o</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc build/repl.o build/duktape.o </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/repl </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-lm</span><span class="token plain"> -Wl,-static -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-s</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Os</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-DCKB_NO_MMU</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_soft_float</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_float_abi_soft</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Iduktape</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ic</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ischema</span><span class="token plain"> -Ideps/ckb-c-stdlib -Ideps/ckb-c-stdlib/molecule </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Wall</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Werror</span><span class="token plain"> c/dump_load.c </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-c</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/dump_load.o</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc build/dump_load.o build/duktape.o </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/dump_load </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-lm</span><span class="token plain"> -Wl,-static -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-s</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">gcc </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Wall</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Werror</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Iduktape</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-O3</span><span class="token plain"> c/native_dump_bytecode.c duktape/duktape.c </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/native_dump_bytecode </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-lm</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Os</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-DCKB_NO_MMU</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_soft_float</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_float_abi_soft</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Iduktape</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ic</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ischema</span><span class="token plain"> -Ideps/ckb-c-stdlib -Ideps/ckb-c-stdlib/molecule </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Wall</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Werror</span><span class="token plain"> c/dump_load_nocleanup.c </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-c</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/dump_load_nocleanup.o</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc build/dump_load_nocleanup.o build/duktape.o </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/dump_load_nocleanup </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-lm</span><span class="token plain"> -Wl,-static -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-s</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">gcc </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Wall</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Werror</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ischema</span><span class="token plain"> -Ideps/ckb-c-stdlib/molecule </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-O3</span><span class="token plain"> c/native_args_assembler.c </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/native_args_assembler</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@0d31cad7a539:/code</span><span class="token comment" style="color:var(--code-comment)"># exit</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">exit</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">ls</span><span class="token plain"> build/</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duktape               dump_load             dump_load_nocleanup   entry.o               native_dump_bytecode  repl.o</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duktape.o             dump_load.o           dump_load_nocleanup.o native_args_assembler repl</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Like the carrot example, the first step here is to deploy duktape script code in a CKB cell:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> data </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> fs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">readFileSync</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"../ckb-duktape/build/duktape"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">byteLength</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token number" style="color:rgb(181, 206, 168)">291440</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">transfer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain">wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token string" style="color:rgb(206, 145, 120)">"292000"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"00000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">data</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token number" style="color:rgb(181, 206, 168)">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> duktapeTxHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> duktapeCodeHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">utils</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">ckbHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">bytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">bytify</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Unlike the carrot example, duktape script code now requires one argument: the JavaScript source you want to execute and the arguments to pass to the JavaScript source code. <code>ckb-duktape</code> provides a small binary tool called <code>native_args_assembler</code> to help us provide the script args from the js file and the js arguments.</p>
<p>First, let's create the script args:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--rm</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-it</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-v</span><span class="token plain"> </span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token variable builtin class-name" style="color:rgb(78, 201, 176)">pwd</span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token plain">:/code nervos/ckb-riscv-gnu-toolchain:xenial </span><span class="token function" style="color:var(--code-function)">bash</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">cd</span><span class="token plain"> /code</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"CKB.debug(</span><span class="token string entity" style="color:rgb(206, 145, 120)">\"</span><span class="token string" style="color:rgb(206, 145, 120)">I'm running in JS</span><span class="token string entity" style="color:rgb(206, 145, 120)">\"</span><span class="token string" style="color:rgb(206, 145, 120)">)"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> test.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> ./build/native_args_assembler </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-f</span><span class="token plain"> test.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">370000000c00000033000000000000001f000000434b422e6465627567282249276d2072756e6e696e6720696e204a5322290a04000000</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Next, copy the script args and build the script:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> duktapeTypeScript </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">codeHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> duktapeCodeHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">hashType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"data"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">args</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x370000000c00000033000000000000001f000000434b422e6465627567282249276d2072756e6e696e6720696e204a5322290a04000000"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Notice that with a different argument, you can create a different duktape powered type script for different use case:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--rm</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-it</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-v</span><span class="token plain"> </span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token variable builtin class-name" style="color:rgb(78, 201, 176)">pwd</span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token plain">:/code nervos/ckb-riscv-gnu-toolchain:xenial </span><span class="token function" style="color:var(--code-function)">bash</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">cd</span><span class="token plain"> /code</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"var a = 1;var b = a + 2;"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">&gt;&gt;</span><span class="token plain"> test.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> ./build/native_args_assembler </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-f</span><span class="token plain"> test.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">330000000c0000002f000000000000001b0000007661722061203d20313b5c6e7661722062203d2061202b20323b0a04000000</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> duktapeTypeScript </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">codeHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> duktapeCodeHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">hashType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"data"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">args</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x330000000c0000002f000000000000001b0000007661722061203d20313b5c6e7661722062203d2061202b20323b0a04000000"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This echos the differences mentioned above on script code vs script: here duktape serves as a script code providing a JavaScript engine, while different script leveraging duktape script code serves different functionalities on chain.</p>
<p>Now we can create a cell with the duktape type script attached:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> duktapeTypeScript </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">codeHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> duktapeCodeHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">hashType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"data"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">args</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x370000000c00000033000000000000001f000000434b422e6465627567282249276d2072756e6e696e6720696e204a5322290a04000000"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">transfer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain">wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token string" style="color:rgb(206, 145, 120)">"200"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"00000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">cellOutput</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">type</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> duktapeTypeScript</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">addCellDep</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">outPoint</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">txHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> duktapeTxHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">index</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">depType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"code"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token number" style="color:rgb(181, 206, 168)">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> txHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We can see that the script executes successfully, and if you have <code>ckb-script</code> module's log level set to <code>debug</code> in your <code>ckb.toml</code> file, you can also notice the following log:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token number" style="color:rgb(181, 206, 168)">2019</span><span class="token plain">-07-15 05:59:13.551 +00:00 http.worker8 DEBUG ckb-script  script group: c35b9fed5fc0dd6eaef5a918cd7a4e4b77ea93398bece4d4572b67a474874641 DEBUG OUTPUT: I'm running </span><span class="token keyword" style="color:var(--code-keyword)">in</span><span class="token plain"> JS</span><span class="token operator" style="color:var(--text-secondary)">!</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now you have successfully deploy a JavaScript engine on CKB, and run JavaScript based script on CKB! Feel free to try any JavaScript code you want here.</p>
<h1>A Thought Exercise</h1>
<p>Now you are familiar with CKB script basics, here's one thought exercise: in this post you've seen what an always-success script looks like, but what about an always-failure script? How small an always-faliure script(and script code) can be?</p>
<p>A hint: this is NOT a gcc flag-tweaking optimization contest, this is merely a thought exercise.</p>
<h1>Next</h1>
<p>I know this is a long post, I hope you have tried this and successfully deployed a script to CKB. In the next post, we will introduce an important topic: how to issue your own user defined tokens(UDT) on CKB. The best part of UDTs on CKB, is that each user can store their UDTs in their own cells, which is different from ERC20 tokens on Ethereum, where everyone's token will have to live in the token issuer's single address. All of this can be achieved by using type scripts alone. If you are interested please stay tuned :)</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduction to CKB Script Programming 3: UDT]]></title>
            <link>https://docs.nervos.org/blog/intro-to-ckb-script-programming-3</link>
            <guid>https://docs.nervos.org/blog/intro-to-ckb-script-programming-3</guid>
            <pubDate>Fri, 06 Sep 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[CKB's cell model and VM enables many new use cases. However that doesn't mean we need to ditch existing ones. One common use in existing blockchains, is to issue new tokens with special purpose/meaning from the token issuer. In Ethereum, we call those ERC20 tokens, let's see how we can build a similar concept in CKB. To distinguish from ERC20, we call the tokens issued in CKB user defined token, or UDT for short.]]></description>
            <content:encoded><![CDATA[<p>CKB's cell model and VM enables many new use cases. However that doesn't mean we need to ditch existing ones. One common use in existing blockchains, is to issue new tokens with special purpose/meaning from the token issuer. In Ethereum, we call those ERC20 tokens, let's see how we can build a similar concept in CKB. To distinguish from ERC20, we call the tokens issued in CKB <code>user defined token</code>, or UDT for short.</p>
<p>This post is written based on current CKB Lina mainnet version now.</p>
<p>While Ethereum has a unique storage space for each contract account, CKB spreads data among multiple cells. A cell's lock &amp; type script then tells which account the cell belongs to, as well as how you can interact with the cell. The consequence of this, is that unlike ERC20 which stores all token users' balances in the ERC20 contract's storage space, in CKB we will need a new design to store the balances of UDT users.</p>
<p>We could, of course, designate a special cell to keep the balances of all UDT users. This solution would look a lot like Ethereum's ERC20 design. But several problems arise:</p>
<ul>
<li>The token issuer would have to provide storage space for keeping all the users' balances. As the number of user grows, the storage space would also grow, in CKB's economic model, this won't be an effective design.</li>
<li>Consider that updating a cell in CKB is essentially destroying the old cell and re-create a new one, having a single cell with all balances would create a bottleneck: every action which needs to update UDT balance would have to update the one and only cell. People will compete on using the cell.</li>
</ul>
<p>While there are solutions which can mitigate or even solve the above problems, we started to question the basic design here: does it really make sense to keep all UDTs in a single place? Once transferred, the UDTs really should belong to the receiver, why should the balance still be kept in a central place?</p>
<p>That leads to our proposed design here:</p>
<ol>
<li>A special type script denotes that the cell stores UDTs.</li>
<li>The first 4 bytes of the cell data contains the amount of UDTs in current cell.</li>
</ol>
<p>This design has several implications:</p>
<ul>
<li>The storage cost for a UDT cell is always constant, it is irrelevant to the amount of UDTs stored in the cell.</li>
<li>A user can transfer either all or part of the UDTs in a cell to others</li>
<li>In practice, there might be numerous cells containing the same UDTs.</li>
<li>The lock script used to guard a UDT is decoupled from the UDT itself.</li>
</ul>
<p>Each token user then keeps their UDTs in their own cells. They are responsible for providing the storage space for the UDTs, and ensure their own tokens are secure. This way UDTs can truly belong to each individual UDT user.</p>
<p>One question remains here: if tokens are stored in numerous cells belonging to each user instead of a single place, how can we ensure the tokens are indeed created by token issuer? What if someone forges tokens on their own? In Ethereum, this is probably a problem, but as we shall see in this post, a type script in CKB can prevent all those attacks, ensuring your token is safe.</p>
<h1>Writing the UDT Script</h1>
<p>Given the above design, a minimal UDT type script should guard the following rules:</p>
<ul>
<li>In a UDT transfer transaction, the sum of UDTs in the output cells should equal the sum of UDTs in the input cells.</li>
<li>Only the token issuer can generate new tokens in the initial token creation process.</li>
</ul>
<p>This might sound a little ambitious, but we will see that with a type script and some CKB's unique design patterns, the eagle can be landed <!-- -->:P</p>
<p>For simplicity, we will write the UDT script here in pure JavaScript, while a C version might help in saving cycles, the functionality will be the same.</p>
<p>First, we will need to loop through all input cells and gather the sum of UDTs:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">diff --git a/udt.js b/udt.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">index e69de29..4a20bd0 100644</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">--- a/udt.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+++ b/udt.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">@@ -0,0 +1,17 @@</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+var input_index = 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+var input_coins = 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+var buffer = new ArrayBuffer(4);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+var ret = CKB.CODE.INDEX_OUT_OF_BOUND;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+while (true) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  ret = CKB.raw_load_cell_data(buffer, 0, input_index, CKB.SOURCE.GROUP_INPUT);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  if (ret === CKB.CODE.INDEX_OUT_OF_BOUND) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+    break;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  if (ret !== 4) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+    throw "Invalid input cell!";</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  var view = new DataView(buffer);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  input_coins += view.getUint32(0, true);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  input_index += 1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>As explained in the previous post, CKB requires us to use a loop to iterate through all inputs in the same <code>group</code> and fetch the data. In C we would use <code>ckb_load_cell_data</code>, which is wrapped into a JS function <code>CKB.raw_load_cell_data</code>. As indicated by the ArrayBuffer, we are only interested in the first 4 bytes of the cell data, since those 4 bytes will contain the amount of UDTs.</p>
<p>Note that here we perform a simple add operation on <code>input_coins</code>, this is very dangerous. We are doing it just for simplicity, in a production setting, you should check if the value will hold in a 32-bit integer value. Higher precision number types should be used if needed.</p>
<p>Similarly, we can fetch the sum of output coins and do the comparision:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">diff --git a/udt.js b/udt.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">index 4a20bd0..e02b993 100644</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">--- a/udt.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+++ b/udt.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">@@ -15,3 +15,23 @@ while (true) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">   input_coins += view.getUint32(0);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">   input_index += 1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+var output_index = 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+var output_coins = 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+while (true) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  ret = CKB.raw_load_cell_data(buffer, 0, output_index, CKB.SOURCE.GROUP_OUTPUT);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  if (ret === CKB.CODE.INDEX_OUT_OF_BOUND) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+    break;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  if (ret !== 4) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+    throw "Invalid output cell!";</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  var view = new DataView(buffer);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  output_coins += view.getUint32(0, true);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  output_index += 1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+if (input_coins !== output_coins) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  throw "Input coins do not equal output coins!";</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This is almost all we need to validate the first rule: the sum of UDTs in the output cells should equal the sum of UDTs in the input cells. In other words, with this type script now, no one will be able to forge new tokens. Isn't that wonderful?</p>
<p>But there's one quirk: when we say <code>no one</code> will be able to forge new tokens, we really mean <code>no one</code>, including the token issuer! This is no good, we need to add an exception so the token issuer can create the tokens first, but no one will be able to do that after. Is there a way to do that?</p>
<p>Yes there is! But the answer reads like a riddle, so please read this paragraph carefully if I lost you the first time: a type script consist of 2 parts: a code hash denoting the actual code, and args used by the type script. 2 type scripts with different args will be treated 2 different type scripts. The trick here, is to allow the token issuer to create a cell with a new type script, that no one will be able to create again, so if we put something in the args part that is not be able to included again, the problem will be solved.</p>
<p>Now think about this problem: what cannot be included in a blockchain twice? An OutPoint in a transaction input! The first time we include an OutPoint as a transaction input, the referenced cell will be consumed, if someone later include it again, it will create a double-spending error, which is exactly what we use blockchain for.</p>
<p>And we have the answer now! The full validation flow of a minimal UDT type script in CKB, is as follows:</p>
<ol>
<li>First gather the sum of all UDTs in the input cells and the sum of all UDTs in the output cells, if they are equaled, the type script exits with a success status.</li>
<li>Check if the first argument of the type script matches the first OutPoint in current transaction, if they match, exit with a success status.</li>
<li>Otherwise exit with a failure status</li>
</ol>
<p>If you are still with me here, you will see that step 1 corresponds to a normal UDT transfer, while step 2 corresponds to the initial token creation process.</p>
<p>This is what we mean by CKB's unique design pattern: by using an input OutPoint as a script argument, we can create a unique script that cannot be forged again:</p>
<ol>
<li>If an attacker tries to use the same argument, the script will validate that the first input OutPoint in the transaction does not match the argument, hence invalidates the transaction;</li>
<li>If the attacker tries to use the same argument and fill in the argument as the first input OutPoint, it will create a double-spent error, also invalidates the transaction;</li>
<li>If the attacker tries to use a different argument, CKB will recognize that the different argument leads to a different type script, hence generating a different UDT.</li>
</ol>
<p>This simple yet powerful pattern thus ensures the UDTs stay safe while enjoying the benefits that they can be transferred freely among many different cells. To the best of our knowledge, this pattern is not possible yet in many other blockchains which claim to be <code>flexible</code> or <code>programmable</code>.</p>
<p>Now we can finally complete the UDT script:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token function" style="color:var(--code-function)">diff</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--git</span><span class="token plain"> a/contract.js b/contract.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">deleted </span><span class="token function" style="color:var(--code-function)">file</span><span class="token plain"> mode </span><span class="token number" style="color:rgb(181, 206, 168)">100644</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">index e69de29</span><span class="token punctuation" style="color:rgb(212, 212, 212)">..</span><span class="token plain">0000000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token function" style="color:var(--code-function)">diff</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--git</span><span class="token plain"> a/udt.js b/udt.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">index e02b993</span><span class="token punctuation" style="color:rgb(212, 212, 212)">..</span><span class="token plain">cd443bf </span><span class="token number" style="color:rgb(181, 206, 168)">100644</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">--- a/udt.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+++ b/udt.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">@@ -1,3 +1,7 @@</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+if </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">CKB.ARGV.length </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  throw </span><span class="token string" style="color:rgb(206, 145, 120)">"Requires only one argument!"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> var input_index </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> var input_coins </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> var buffer </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> new ArrayBuffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">4</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">@@ -33,5 +37,17 @@ </span><span class="token keyword" style="color:var(--code-keyword)">while</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">true</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">input_coins </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> output_coins</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">-  throw </span><span class="token string" style="color:rgb(206, 145, 120)">"Input coins do not equal output coins!"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:var(--text-secondary)">!</span><span class="token variable punctuation" style="color:rgb(212, 212, 212)">((</span><span class="token variable" style="color:rgb(156, 220, 254)">input_index </span><span class="token variable operator" style="color:var(--text-secondary)">==</span><span class="token variable operator" style="color:var(--text-secondary)">=</span><span class="token variable" style="color:rgb(156, 220, 254)"> </span><span class="token variable number" style="color:rgb(181, 206, 168)">0</span><span class="token variable punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token variable" style="color:rgb(156, 220, 254)"> </span><span class="token variable operator" style="color:var(--text-secondary)">&amp;&amp;</span><span class="token variable" style="color:rgb(156, 220, 254)"> </span><span class="token variable punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token variable" style="color:rgb(156, 220, 254)">output_index </span><span class="token variable operator" style="color:var(--text-secondary)">==</span><span class="token variable operator" style="color:var(--text-secondary)">=</span><span class="token variable" style="color:rgb(156, 220, 254)"> </span><span class="token variable number" style="color:rgb(181, 206, 168)">1</span><span class="token variable punctuation" style="color:rgb(212, 212, 212)">))</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+    throw </span><span class="token string" style="color:rgb(206, 145, 120)">"Invalid token issuing mode!"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  var first_input </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> CKB.load_input</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain">, </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain">, CKB.SOURCE.INPUT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">typeof first_input </span><span class="token operator" style="color:var(--text-secondary)">==</span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"number"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+    throw </span><span class="token string" style="color:rgb(206, 145, 120)">"Cannot fetch the first input"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  var hex_input_outpoint </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> Array.prototype.map</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+   .call</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">new Uint8Array</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">first_input</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">, </span><span class="token keyword" style="color:var(--code-keyword)">function</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">x</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+     </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"00"</span><span class="token plain"> + x.toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">16</span><span class="token punctuation" style="color:rgb(212, 212, 212)">))</span><span class="token plain">.slice</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">-2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+   </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+   .join</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">""</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+   .slice</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">16</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> // remove the first </span><span class="token number" style="color:rgb(181, 206, 168)">8</span><span class="token plain"> bytes of since</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  var outpoint_arg </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> new TextDecoder</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">.decode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">CKB.ARGV</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">outpoint_arg </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token plain"> hex_input_outpoint</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+    throw </span><span class="token string" style="color:rgb(206, 145, 120)">"Invalid creation argument!"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">+  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>And that's it, with 53 lines of code or 1372 bytes, we've completed a minimal UDT type script in CKB. Notice I don't even use a minimizer here, with any decent JS minimizer, we should be able to get a much more compact type script. Of course this is a production ready script, but it suffices to show a simple script is enough to handle important tasks in CKB.</p>
<h1>Deploying to CKB</h1>
<p>I'm not like <a href="https://hacks.mozilla.org/2019/09/debugging-webassembly-outside-of-the-browser/" target="_blank" rel="noopener noreferrer">some other organizations</a> who prefer to only show you a video and a provocative post which hide how they did it and the accompanying problems. I believe no post is fun without actual code and steps to play with it. And here's how you can use the above UDT script on CKB:</p>
<p>In case you might need it, here's the full UDT script without diff format:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">cat</span><span class="token plain"> udt.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">CKB.ARGV.length </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  throw </span><span class="token string" style="color:rgb(206, 145, 120)">"Requires only one argument!"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">var input_index </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">var input_coins </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">var buffer </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> new ArrayBuffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">4</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">var ret </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> CKB.CODE.INDEX_OUT_OF_BOUND</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token keyword" style="color:var(--code-keyword)">while</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">true</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ret </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> CKB.raw_load_cell_data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer, </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain">, input_index, CKB.SOURCE.GROUP_INPUT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ret </span><span class="token operator" style="color:var(--text-secondary)">==</span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> CKB.CODE.INDEX_OUT_OF_BOUND</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">break</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ret </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">4</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    throw </span><span class="token string" style="color:rgb(206, 145, 120)">"Invalid input cell!"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  var view </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> new DataView</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  input_coins </span><span class="token operator" style="color:var(--text-secondary)">+=</span><span class="token plain"> view.getUint32</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain">, </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  input_index </span><span class="token operator" style="color:var(--text-secondary)">+=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">var output_index </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">var output_coins </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token keyword" style="color:var(--code-keyword)">while</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">true</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ret </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> CKB.raw_load_cell_data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer, </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain">, output_index, CKB.SOURCE.GROUP_OUTPUT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ret </span><span class="token operator" style="color:var(--text-secondary)">==</span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> CKB.CODE.INDEX_OUT_OF_BOUND</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">break</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ret </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">4</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    throw </span><span class="token string" style="color:rgb(206, 145, 120)">"Invalid output cell!"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  var view </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> new DataView</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  output_coins </span><span class="token operator" style="color:var(--text-secondary)">+=</span><span class="token plain"> view.getUint32</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain">, </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  output_index </span><span class="token operator" style="color:var(--text-secondary)">+=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">input_coins </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> output_coins</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:var(--text-secondary)">!</span><span class="token variable punctuation" style="color:rgb(212, 212, 212)">((</span><span class="token variable" style="color:rgb(156, 220, 254)">input_index </span><span class="token variable operator" style="color:var(--text-secondary)">==</span><span class="token variable operator" style="color:var(--text-secondary)">=</span><span class="token variable" style="color:rgb(156, 220, 254)"> </span><span class="token variable number" style="color:rgb(181, 206, 168)">0</span><span class="token variable punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token variable" style="color:rgb(156, 220, 254)"> </span><span class="token variable operator" style="color:var(--text-secondary)">&amp;&amp;</span><span class="token variable" style="color:rgb(156, 220, 254)"> </span><span class="token variable punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token variable" style="color:rgb(156, 220, 254)">output_index </span><span class="token variable operator" style="color:var(--text-secondary)">==</span><span class="token variable operator" style="color:var(--text-secondary)">=</span><span class="token variable" style="color:rgb(156, 220, 254)"> </span><span class="token variable number" style="color:rgb(181, 206, 168)">1</span><span class="token variable punctuation" style="color:rgb(212, 212, 212)">))</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    throw </span><span class="token string" style="color:rgb(206, 145, 120)">"Invalid token issuing mode!"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  var first_input </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> CKB.load_input</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain">, </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain">, CKB.SOURCE.INPUT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">typeof first_input </span><span class="token operator" style="color:var(--text-secondary)">==</span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"number"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    throw </span><span class="token string" style="color:rgb(206, 145, 120)">"Cannot fetch the first input"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  var hex_input_outpoint </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> Array.prototype.map</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    .call</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">new Uint8Array</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">first_input</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">, </span><span class="token keyword" style="color:var(--code-keyword)">function</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">x</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"00"</span><span class="token plain"> + x.toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">16</span><span class="token punctuation" style="color:rgb(212, 212, 212)">))</span><span class="token plain">.slice</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">-2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    .join</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">""</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    .slice</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">16</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> // remove the first </span><span class="token number" style="color:rgb(181, 206, 168)">8</span><span class="token plain"> bytes of since</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  var outpoint_arg </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> new TextDecoder</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">.decode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">CKB.ARGV</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">outpoint_arg </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token plain"> hex_input_outpoint</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    throw </span><span class="token string" style="color:rgb(206, 145, 120)">"Invalid creation argument!"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In order to run JavaScript, let's first deploy duktape on CKB:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> fs </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">require</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"fs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> data </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> fs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">readFileSync</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"../ckb-duktape/build/duktape"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">byteLength</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token number" style="color:rgb(181, 206, 168)">291440</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">transfer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"292000"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"00000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">data</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> duktapeTxHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> duktapeCodeHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">utils</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">ckbHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">bytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">bytify</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>First, let's create a UDT with 1000000 tokens</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">transfer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"1820"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"00000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> blockchain </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">require</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"@ckb-lumos/base"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">blockchain</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> outPointBuf </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> blockchain</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access maybe-class-name">OutPoint</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">pack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"inputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">outPoint</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> outPointHex </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token maybe-class-name">Buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword module" style="color:var(--code-keyword)">from</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">outPointBuf</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> outPointHex</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">6a5f904a6f6ec270b6dde3add221aa8a82120e2e98ea6dac59160dd09359084201000000</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><code>outPointHex</code> is part of the args in the Script, we will use a small tool to build the whole js Script args:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token builtin class-name" style="color:rgb(78, 201, 176)">cd</span><span class="token plain"> ckb-duktape</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token function" style="color:var(--code-function)">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--rm</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-it</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-v</span><span class="token plain"> </span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token variable builtin class-name" style="color:rgb(78, 201, 176)">pwd</span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token plain">:/code nervos/ckb-riscv-gnu-toolchain:xenial </span><span class="token function" style="color:var(--code-function)">bash</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@0d31cad7a539:~</span><span class="token comment" style="color:var(--code-comment)"># cd /code</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@0d31cad7a539:/code</span><span class="token comment" style="color:var(--code-comment)"># ./build/native_args_assembler -f udt.js -t 6a5f904a6f6ec270b6dde3add221aa8a82120e2e98ea6dac59160dd09359084201000000</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">b50600000c00000061060000000000004d06000069662028434b422e415247562e6c656e67746820213d3d203129207b0a20207468726f7720225265717569726573206f6e6c79206f6e6520617267756d656e7421223b0a7d0a0a76617220696e7075745f696e646578203d20303b0a76617220696e7075745f636f696e73203d20303b0a76617220627566666572203d206e65772041727261794275666665722834293b0a76617220726574203d20434b422e434f44452e494e4445585f4f55545f4f465f424f554e443b0a0a7768696c6520287472756529207b0a2020726574203d20434b422e7261775f6c6f61645f63656c6c5f64617461286275666665722c20302c20696e7075745f696e6465782c20434b422e534f555243452e47524f55505f494e505554293b0a202069662028726574203d3d3d20434b422e434f44452e494e4445585f4f55545f4f465f424f554e4429207b0a20202020627265616b3b0a20207d0a20206966202872657420213d3d203429207b0a202020207468726f772022496e76616c696420696e7075742063656c6c21223b0a20207d0a20207661722076696577203d206e657720446174615669657728627566666572293b0a2020696e7075745f636f696e73202b3d20766965772e67657455696e74333228302c2074727565293b0a2020696e7075745f696e646578202b3d20313b0a7d0a0a766172206f75747075745f696e646578203d20303b0a766172206f75747075745f636f696e73203d20303b0a0a7768696c6520287472756529207b0a2020726574203d20434b422e7261775f6c6f61645f63656c6c5f64617461280a202020206275666665722c0a20202020302c0a202020206f75747075745f696e6465782c0a20202020434b422e534f555243452e47524f55505f4f55545055540a2020293b0a202069662028726574203d3d3d20434b422e434f44452e494e4445585f4f55545f4f465f424f554e4429207b0a20202020627265616b3b0a20207d0a20206966202872657420213d3d203429207b0a20202020434b422e646562756728726574293b0a202020207468726f772022496e76616c6964206f75747075742063656c6c21223b0a20207d0a20207661722076696577203d206e657720446174615669657728627566666572293b0a20206f75747075745f636f696e73202b3d20766965772e67657455696e74333228302c2074727565293b0a20206f75747075745f696e646578202b3d20313b0a7d0a0a69662028696e7075745f636f696e7320213d3d206f75747075745f636f696e7329207b0a2020696620282128696e7075745f696e646578203d3d3d2030202626206f75747075745f696e646578203d3d3d20312929207b0a202020207468726f772022496e76616c696420746f6b656e2069737375696e67206d6f646521223b0a20207d0a20207661722066697273745f696e707574203d20434b422e6c6f61645f696e70757428302c20302c20434b422e534f555243452e494e505554293b0a202069662028747970656f662066697273745f696e707574203d3d3d20226e756d6265722229207b0a202020207468726f77202243616e6e6f742066657463682074686520666972737420696e707574223b0a20207d0a2020766172206865785f696e7075745f6f7574706f696e74203d2041727261792e70726f746f747970652e6d61700a202020202e63616c6c286e65772055696e743841727261792866697273745f696e707574292c2066756e6374696f6e20287829207b0a20202020202072657475726e202822303022202b20782e746f537472696e6728313629292e736c696365282d32293b0a202020207d290a202020202e6a6f696e282222290a202020202e736c696365283136293b202f2f2072656d6f7665207468652066697273742038206279746573206f662073696e63650a2020766172206f7574706f696e745f617267203d206e657720546578744465636f64657228292e6465636f646528434b422e415247565b305d293b0a2020696620286f7574706f696e745f61726720213d206865785f696e7075745f6f7574706f696e7429207b0a20202020434b422e6465627567286f7574706f696e745f617267290a20202020434b422e6465627567286865785f696e7075745f6f7574706f696e74290a202020207468726f772022496e76616c6964206372656174696f6e20617267756d656e7421223b0a20207d0a7d0a540000000800000048000000366135663930346136663665633237306236646465336164643232316161386138323132306532653938656136646163353931363064643039333539303834323031303030303030</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Copy this args to the Script args:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> duktapeUdtTypeScript </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">codeHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> duktapeCodeHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">hashType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"data"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">args</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0xb50600000c00000061060000000000004d06000069662028434b422e415247562e6c656e67746820213d3d203129207b0a20207468726f7720225265717569726573206f6e6c79206f6e6520617267756d656e7421223b0a7d0a0a76617220696e7075745f696e646578203d20303b0a76617220696e7075745f636f696e73203d20303b0a76617220627566666572203d206e65772041727261794275666665722834293b0a76617220726574203d20434b422e434f44452e494e4445585f4f55545f4f465f424f554e443b0a0a7768696c6520287472756529207b0a2020726574203d20434b422e7261775f6c6f61645f63656c6c5f64617461286275666665722c20302c20696e7075745f696e6465782c20434b422e534f555243452e47524f55505f494e505554293b0a202069662028726574203d3d3d20434b422e434f44452e494e4445585f4f55545f4f465f424f554e4429207b0a20202020627265616b3b0a20207d0a20206966202872657420213d3d203429207b0a202020207468726f772022496e76616c696420696e7075742063656c6c21223b0a20207d0a20207661722076696577203d206e657720446174615669657728627566666572293b0a2020696e7075745f636f696e73202b3d20766965772e67657455696e74333228302c2074727565293b0a2020696e7075745f696e646578202b3d20313b0a7d0a0a766172206f75747075745f696e646578203d20303b0a766172206f75747075745f636f696e73203d20303b0a0a7768696c6520287472756529207b0a2020726574203d20434b422e7261775f6c6f61645f63656c6c5f64617461280a202020206275666665722c0a20202020302c0a202020206f75747075745f696e6465782c0a20202020434b422e534f555243452e47524f55505f4f55545055540a2020293b0a202069662028726574203d3d3d20434b422e434f44452e494e4445585f4f55545f4f465f424f554e4429207b0a20202020627265616b3b0a20207d0a20206966202872657420213d3d203429207b0a20202020434b422e646562756728726574293b0a202020207468726f772022496e76616c6964206f75747075742063656c6c21223b0a20207d0a20207661722076696577203d206e657720446174615669657728627566666572293b0a20206f75747075745f636f696e73202b3d20766965772e67657455696e74333228302c2074727565293b0a20206f75747075745f696e646578202b3d20313b0a7d0a0a69662028696e7075745f636f696e7320213d3d206f75747075745f636f696e7329207b0a2020696620282128696e7075745f696e646578203d3d3d2030202626206f75747075745f696e646578203d3d3d20312929207b0a202020207468726f772022496e76616c696420746f6b656e2069737375696e67206d6f646521223b0a20207d0a20207661722066697273745f696e707574203d20434b422e6c6f61645f696e70757428302c20302c20434b422e534f555243452e494e505554293b0a202069662028747970656f662066697273745f696e707574203d3d3d20226e756d6265722229207b0a202020207468726f77202243616e6e6f742066657463682074686520666972737420696e707574223b0a20207d0a2020766172206865785f696e7075745f6f7574706f696e74203d2041727261792e70726f746f747970652e6d61700a202020202e63616c6c286e65772055696e743841727261792866697273745f696e707574292c2066756e6374696f6e20287829207b0a20202020202072657475726e202822303022202b20782e746f537472696e6728313629292e736c696365282d32293b0a202020207d290a202020202e6a6f696e282222290a202020202e736c696365283136293b202f2f2072656d6f7665207468652066697273742038206279746573206f662073696e63650a2020766172206f7574706f696e745f617267203d206e657720546578744465636f64657228292e6465636f646528434b422e415247565b305d293b0a2020696620286f7574706f696e745f61726720213d206865785f696e7075745f6f7574706f696e7429207b0a20202020434b422e6465627567286f7574706f696e745f617267290a20202020434b422e6465627567286865785f696e7075745f6f7574706f696e74290a202020207468726f772022496e76616c6964206372656174696f6e20617267756d656e7421223b0a20207d0a7d0a540000000800000048000000366135663930346136663665633237306236646465336164643232316161386138323132306532653938656136646163353931363064643039333539303834323031303030303030"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> bytes </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">require</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"@ckb-lumos/lumos/codec"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">bytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> </span><span class="token maybe-class-name">Uint32LE</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">require</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"@ckb-lumos/codec"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">number</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access maybe-class-name">Uint32LE</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">cellOutput</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">type</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> duktapeUdtTypeScript</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">data</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> bytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">hexify</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token maybe-class-name">Uint32LE</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">pack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">1000000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">addCellDep</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">outPoint</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">txHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> duktapeTxHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">index</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">depType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"code"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> rootUdtTxHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>If we tried to submit the same transaction again, double-spent error will prevent us from forging the same token:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token constant" style="color:var(--code-constant)">CKB</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token known-class-name class-name" style="color:rgb(78, 201, 176)">RPCError</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> jsonrpc error</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token parameter">code</span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">3</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token parameter">message</span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token string" style="color:rgb(206, 145, 120)">"UnresolvableTransaction(Dead(OutPoint(0x0b607e9599f23a8140d428bd24880e5079de1f0ee931618b2f84decf2600383601000000)))"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>And no matter how we tried, we cannot create another cell which forges the same UDT token.</p>
<p>Now we can try transfering UDTs to another account. First let's try creating one which has more output UDTs than input UDTs</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> inputOutpoint </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">txHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> rootUdtTxHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">index</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> udtCellWithStatus </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">getLiveCell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">inputOutpoint</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> blockHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">getTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">rootUdtTxHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">txStatus</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">blockHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> blockNumber </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">getHeader</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">blockHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">number</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> input </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">outPoint</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> inputOutpoint</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">data</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> udtCellWithStatus</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">content</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">cellOutput</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> udtCellWithStatus</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">output</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    blockNumber</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> output </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">data</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> bytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">hexify</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token maybe-class-name">Uint32LE</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">pack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">2000000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">cellOutput</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> udtCellWithStatus</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">output</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"inputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">inputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> inputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">push</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">push</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">output</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"witnesses"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">witnesses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> witnesses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">push</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"0x55000000100000005500000055000000410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">addCellDep</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">outPoint</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">txHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> duktapeTxHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">index</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">depType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"code"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">addCellDep</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">outPoint</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">txHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">config</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token constant" style="color:var(--code-constant)">TESTNET</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token constant" style="color:var(--code-constant)">SCRIPTS</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">'SECP256K1_BLAKE160'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">'TX_HASH'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">index</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">config</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token constant" style="color:var(--code-constant)">TESTNET</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token constant" style="color:var(--code-constant)">SCRIPTS</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">'SECP256K1_BLAKE160'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">'INDEX'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">depType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">config</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token constant" style="color:var(--code-constant)">TESTNET</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token constant" style="color:var(--code-constant)">SCRIPTS</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">'SECP256K1_BLAKE160'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">'DEP_TYPE'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token constant" style="color:var(--code-constant)">CKB</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token known-class-name class-name" style="color:rgb(78, 201, 176)">RPCError</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> jsonrpc error</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token parameter">code</span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">3</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token parameter">message</span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token string" style="color:rgb(206, 145, 120)">"InvalidTx(ScriptFailure(ValidationFailure(101)))"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Here we tried to send another user 2000000 UDTs, of course this should trigger an error since we are trying to forge more tokens. But with slight modification, we can show that a UDT transferring transaction works if you respect the sum verification rule:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">cellOutput</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">type</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">cellOutput</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">type</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">data</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> bytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">hexify</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token maybe-class-name">Uint32LE</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">pack</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">1000000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h1>Flexible Rules</h1>
<p>The UDT script shown here serves just as an example, in reality, dapps might be more complicated and requires more functions. You are also free to include more features for your UDT scripts depending on your needs, some examples include:</p>
<ul>
<li>Here we strictly ensure that the sum of output UDTs equals the sum of input UDTs, but in some cases, it might be enough just to ensure the sum of output UDTs does not exceed the sum of input UDTs. In order words, when not needed, a user can choose to burn the UDTs for the capacities.</li>
<li>The above UDT script doesn't allow issuing more tokens after the initial creation process, but there might be another type of UDT that allows more issurance from the token issuer. This is also possible on CKB, the actual way to solve this task, is left as an exercise here :)</li>
<li>Here we limit the script to only create one cell in the initial token creation process, it's also possible to create multiple cells to spread the usage in the initial token creation process.</li>
<li>While we only cover ERC20 here, ERC721 should also be totally possible.</li>
</ul>
<p>Notice those are just some examples, the actual ways of using CKB script are limitless here. We are more than happy to see cases where CKB dapp developers amaze us with interesting usage of CKB scripts.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduction to CKB Script Programming 4: WebAssembly on CKB]]></title>
            <link>https://docs.nervos.org/blog/intro-to-ckb-script-programming-4</link>
            <guid>https://docs.nervos.org/blog/intro-to-ckb-script-programming-4</guid>
            <pubDate>Wed, 09 Oct 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Since we made the choice to build CKB's virtual machine with RISC-V, we've been getting a question almost everyday: why don't you build your virtual machine on WebAssembly like everyone else does?]]></description>
            <content:encoded><![CDATA[<p>Since we made the choice to build CKB's virtual machine with RISC-V, we've been getting a question almost everyday: why don't you build your virtual machine on WebAssembly like everyone else does?</p>
<p>There're many reasons behind this choice, making it a perfect choice for another article or even a conference talk. But fundamentally there lies one important reason: building software is all about finding the right abstraction, and we believe RISC-V is a better abstraction than WebAssembly for public permissionless blockchain.</p>
<p>While WebAssembly is already a huge advancement over higher level programming langauges as well as the first generation blockchain virtual machines, RISC-V works at a much lower level than WebAssembly, making it a more suitable choice for public blockchains which are designed to run for decades to come.</p>
<p>But that still leaves one question unanswered: a significant portion of the blockchain industry is betting on WebAssembly, contributing an (arguably) better ecosystem building on WebAssembly powered dapps. How can CKB compete with that? As mentioned above, RISC-V is actually a lower level of abstraction than WebAssembly, we can port existing WebAssembly programs, and run them on CKB VM directly. This way, we can enjoy the flexibility and stability provided by RISC-V, while also embracing the WebAssembly ecosystem.</p>
<p>In this article, we will show how you can run WebAssembly programs in CKB VM, we will also show that it actually has more benefits running this way than directly using a WebAssembly VM.</p>
<p>Personally, while I believe WebAssembly has some interesting features enabling different use cases, I don't believe WebAssembly has a better ecosystem in the blockchain space. If you look around, there are probably just 2 mature choices for building dapps in a WebAssembly-based blockchain: Rust, and AssemblyScript. People keep bragging about WebAssembly's ability to support arbitrary languages in a single abstract VM(I personally refuse to call WebAssembly low-level VM), but it really just comes down to one of the 2 choices here to build a real dapp. I think we probably have different definitions if we can call 2 supported languages a good VM ecosystem. There are some <a href="https://github.com/tweag/asterius" target="_blank" rel="noopener noreferrer">other languages</a> playing catching up here, but they are not yet at stable phase to count as a richful ecosystem. While some <a href="https://github.com/forest-lang/forest-compiler" target="_blank" rel="noopener noreferrer">interesting langauges</a> have potentials in a WebAssembly based environment, no one pays attention to support them. And if you look hard enough, it also remains a question if 2 different blockchains using WebAssembly can share contracts with each other. Of course one might say: "well it's just a matter of time, given time more vibrant WebAssembly ecosystem will sprout", but the same argument could apply anywhere: why given time, an ecosystem for RISC-V won't be better?</p>
<p>But enough for the rant, let's just assume for now, WebAssembly does have a blockchain ecosystem, we can show that the 2 widely used choices, AssemblyScript and Rust, are all supported in a CKB VM environment.</p>
<p>I believe no words speak better than a demo you can play with. So let's try the official AssemblyScript and run the compiled program on CKB. We will just use the official example in AssemblyScript's <a href="https://www.assemblyscript.org/introduction.html" target="_blank" rel="noopener noreferrer">introduction page</a>:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat fib.ts</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">export function fib(n: i32): i32 {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  var a = 0, b = 1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    for (let i = 0; i &lt; n; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        let t = a + b; a = b; b = t;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return b;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Please refer to AssemblyScript's documentation on how to install it. For convenience, I have some steps that you can just copy-paste here.</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/AssemblyScript/assemblyscript.git</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd assemblyscript</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm install</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ bin/asc ../fib.ts -b ../fib.wasm -O3</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ..</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We have a compiled WebAssembly program to use here. What we can do then, is invoke a program named <a href="https://github.com/WebAssembly/wabt/tree/master/wasm2c" target="_blank" rel="noopener noreferrer">wasm2c</a> to compile it to C source file, then compile it via a RISC-V compiler to a RISC-V program, and run it on CKB VM.</p>
<p>I'm sure you would ask: but this is a hack! It sort of does a decompilation of the WASM program then make it work, you are cheating here. The answer to this question, is yes and no:</p>
<ul>
<li>On the one hand, yes I'm cheating here, but the question I'm gonna raise in response is: all we should care, is the end result, if the result is good enough, why should we care if this is cheating? In addition, modern compiler is already complicated enough like a total black box, how can we be sure this decompilation will achieve worse result?</li>
<li>On the other hand, this is just one way of transforming WebAssembly into RISC-V. There're numerous other ways in which you can achieve the same result. We will come back to this in the Recap section later.</li>
</ul>
<p>Let's fire up <code>wasm2c</code> and transform the WebAssembly program:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone --recursive https://github.com/WebAssembly/wabt</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd wabt</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ mkdir build</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd build</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cmake ..</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cmake --build .</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ../..</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ wabt/bin/wasm2c fib.wasm -o fib.c</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You will see a pair of <code>fib.c</code> and <code>fib.h</code> file in current directory, they contain the transformation result of the WebAssembly program, and when compiled and called correctly, they will achieve the same feature as the WebAssembly program.</p>
<p>We can use a small wrapper C file to invoke the WebAssembly program:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat main.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;stdio.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;stdlib.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "fib.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">int main(int argc, char** argv) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (argc &lt; 2) return 2;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  u8 x = atoi(argv[1]);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  init();</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  u8 result = Z_fibZ_ii(x);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return result;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This just reads an integer from a CLI argument, invokes the fibonacci function in the WebAssembly program, then return the result. Let's try compile it first:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ sudo docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:xenial bash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(docker) $ cd /code</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(docker) $ riscv64-unknown-elf-gcc -o fib_riscv64 -O3 -g main.c fib.c /code/wabt/wasm2c/wasm-rt-impl.c -I /code/wabt/wasm2c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccfUDYhE.o: in function `__retain':</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/code/fib.c:1602: undefined reference to `Z_envZ_abortZ_viiii'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccfUDYhE.o: in function `i32_load':</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/code/fib.c:42: undefined reference to `Z_envZ_abortZ_viiii'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccfUDYhE.o: in function `f17':</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/code/fib.c:1564: undefined reference to `Z_envZ_abortZ_viiii'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /code/fib.c:1564: undefined reference to `Z_envZ_abortZ_viiii'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccfUDYhE.o: in function `f6':</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/code/fib.c:1011: undefined reference to `Z_envZ_abortZ_viiii'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccfUDYhE.o:/code/fib.c:1012: more undefined references to `Z_envZ_abortZ_viiii' follow</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">collect2: error: ld returned 1 exit status</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(docker) $ exit</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>As shown above, there's an error here. It tells us there's an <code>Z_envZ_abortZ_viiii</code> function not defined. Let's dive into why this happened.</p>
<p>First, let's transform the original WebAssembly file into a human readable form:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ wabt/bin/wasm2wat fib.wasm -o fib.wast</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat fib.wast | grep "(import"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(import "env" "abort" (func (;0;) (type 2)))</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>So the problem is that WebAssembly can import external functions, when invoking, provides additional functionalities. In fact, the famous <a href="https://wasi.dev/" target="_blank" rel="noopener noreferrer">WASI</a> is implemented based on the <code>import</code> feature. Later we shall see <code>import</code> can be used to implement more interesting features that are not possible in WebAssembly based blockchain virtual machines.</p>
<p>For now, let's provide an abort implementation to fix the error:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat main.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;stdio.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;stdlib.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "fib.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">void (*Z_envZ_abortZ_viiii)(u32, u32, u32, u32);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">void env_abort(u32 a, u32 b, u32 c, u32 d) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  abort();</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">int main(int argc, char** argv) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (argc &lt; 2) return 2;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  u8 x = atoi(argv[1]);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  Z_envZ_abortZ_viiii = &amp;env_abort;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  init();</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  u8 result = Z_fibZ_ii(x);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return result;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ sudo docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:xenial bash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(docker) $ cd /code</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(docker) $ riscv64-unknown-elf-gcc -o fib_riscv64 -O3 -g main.c fib.c /code/wabt/wasm2c/wasm-rt-impl.c -I /code/wabt/wasm2c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(docker) $ exit</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Of course you can test the compiled <code>fib_riscv64</code> program on CKB. But as a trick, there's a simple CKB VM <a href="https://github.com/nervosnetwork/ckb-vm-test-suite/tree/master/binary/src" target="_blank" rel="noopener noreferrer">binary</a> in the <a href="https://github.com/nervosnetwork/ckb-vm-test-suite" target="_blank" rel="noopener noreferrer">test suite</a> we can use the run this particular program. It's worth mentioning that this CKB VM binary works slightly different from the VM in CKB. It suffices to test WebAssembly programs in current example. But for testing proper CKB script, you might want to use the newly built <a href="https://github.com/nervosnetwork/ckb-standalone-debugger" target="_blank" rel="noopener noreferrer">standalone debugger</a>, which follows all CKB semantics. Later posts will explain how the debugger works.</p>
<p>Let's try compile the binary in test suite and run the program:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone --recursive https://github.com/nervosnetwork/ckb-vm-test-suite</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ckb-vm-test-suite</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/nervosnetwork/ckb-vm</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd binary</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cargo build --release</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ../..</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ckb-vm-test-suite/binary/target/release/asm64 fib_riscv64 5</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Error result: Ok(8)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ckb-vm-test-suite/binary/target/release/asm64 fib_riscv64 10</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Error result: Ok(89)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The error here is slightly misleading, the binary will treat any non-zero result from the program as errors. Since the program tested return the fibonacci calculation result as the return value, the binary will treat the return value(which is most likely non-zero) as error, but we can see that the actual error value contains the correct fibonacci value.</p>
<p>Now we proves AssemblyScript program indeed works on CKB VM! I'm sure more complicated programs might run into errors which need separate tweaking, but you already get the workflow and know where to look for when error happens :)</p>
<h1>Rust</h1>
<p>We've already seen simpler examples in the AssemblyScript part. Let's try something more interesting in the Rust part: can we do a whole signature verification in Rust code?</p>
<p>Turns out yes we can! But this is signficantly more than what we can fit in a blog post. I've prepared a <a href="https://github.com/nervosnetwork/wasm-secp256k1-test" target="_blank" rel="noopener noreferrer">demo project</a> showcasing this. It uses a pure Rust implemented <a href="https://github.com/paritytech/libsecp256k1" target="_blank" rel="noopener noreferrer">secp256k1 library</a> to do signature verification. If you follow the instructions in the README, you can reproduce the exact steps of the following:</p>
<ul>
<li>Compile a complicated Rust program into WebAssembly</li>
<li>Transform the WebAssembly program into RISC-V</li>
<li>Run the resulting RISC-V program on CKB VM</li>
</ul>
<h1>Enhancements to WebAssembly</h1>
<p>There's one additional thing we want to mention: if you check out the <code>bindgen</code> branch of the <a href="https://github.com/nervosnetwork/wasm-secp256k1-test/tree/bindgen" target="_blank" rel="noopener noreferrer">Rust secp256k1 demo repository</a>, and try the same steps, you will run into the following errors:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccYMiL3C.o: in function `core::result::unwrap_failed':</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/code/secp.c:342: undefined reference to `Z___wbindgen_placeholder__Z___wbindgen_describeZ_vi'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /code/secp.c:344: undefined reference to `Z___wbindgen_placeholder__Z___wbindgen_describeZ_vi'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /code/secp.c:344: undefined reference to `Z___wbindgen_placeholder__Z___wbindgen_describeZ_vi'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /code/secp.c:347: undefined reference to `Z___wbindgen_placeholder__Z___wbindgen_describeZ_vi'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /code/secp.c:350: undefined reference to `Z___wbindgen_placeholder__Z___wbindgen_describeZ_vi'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccYMiL3C.o:/code/secp.c:353: more undefined references to `Z___wbindgen_placeholder__Z___wbindgen_describeZ_vi' follow</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccYMiL3C.o: in function `i32_store':</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/code/secp.c:56: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_set_nullZ_vi'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccYMiL3C.o: in function `i32_load':</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/code/secp.c:42: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_set_nullZ_vi'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccYMiL3C.o: in function `i32_store':</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/code/secp.c:56: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_set_nullZ_vi'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /code/secp.c:56: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_set_nullZ_vi'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccYMiL3C.o: in function `i32_load':</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/code/secp.c:42: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_growZ_ii'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /code/secp.c:42: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_growZ_ii'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">collect2: error: ld returned 1 exit status</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Following the same steps in the AssemblyScript examples, we can certain <code>imports</code> in the WebAssembly file:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ wabt/bin/wasm2wat wasm_secp256k1_test.wasm -o secp.wat</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat secp.wat | grep "(import"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(import "__wbindgen_placeholder__" "__wbindgen_describe" (func $__wbindgen_describe (type 3)))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(import "__wbindgen_anyref_xform__" "__wbindgen_anyref_table_grow" (func $__wbindgen_anyref_table_grow (type 4)))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(import "__wbindgen_anyref_xform__" "__wbindgen_anyref_table_set_null" (func $__wbindgen_anyref_table_set_null (type 3)))</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Those are actually binding environment functions needed in the Rust <a href="https://github.com/rustwasm/wasm-bindgen" target="_blank" rel="noopener noreferrer">wasm-bindgen</a>. We will continue to work to provide the bindings compatible with CKB environment. But let's take a step back and think about this now: the environment functions needed here, are not part of WebAssembly standard. What's required in the standard, is that when an import entry cannot be found, the WebAssembly VM is expected to halt execution with an errors. To achieve different features, different WebAssembly based blockchains might inject different imports here, making it hard to write a WebAssembly program that's compatible across different blockchains.</p>
<p>In the CKB environment, however, we can attach any environment functions as we like, hence supporting all WebAssembly programs which are targeting different blockchains. What's more, we can use <code>imports</code> as we like to introduce new features to an existing WebAssembly programs, since the import functions are shipped together with the WebAssembly program, CKB itself doesn't have to do anything to support this, all the magic happens right within a single CKB script. For a WebAssembly powered blockchain, those environment functions are most likely to be fixed and part of the consensus rules, you cannot introduce new ones as you wish. Similarly, this tranformation based workflow on CKB will make it far easier to support new WebAssembly features, such as garbage collection, or threading, it really is just a matter of shipping the support features you need as part of your CKB script, there's no need to wait another 6 months for the next hardfork when a WebAssembly virtual machine gets updated, if it's updated.</p>
<h1>It's About Ease of Implementation</h1>
<p>You might have one question: "I get it, you have WebAssembly on RISC-V, but I could also have RISC-V on WebAssembly! WebAssembly is flexible!". In a sense, this is true, once a language or a VM surpasses a certain level of flexibility, it can be used to build many (even crazy) things. The first version of <a href="https://bellard.org/jslinux/tech.html" target="_blank" rel="noopener noreferrer">jslinux</a> which emulates full x86 was even written in pure JavaScript! But the other side of the problem, is ease of implementation. Building WebAssembly on RISC-V feels more natural, since WebAssembly abstracts at a higher level with many high level features, such as higher level contrl flows, garbage collection, etc. RISC-V, on the other hand, really emulates what a real CPU can do, it is a very thin layer on top of the actual CPU running inside of the computer. So while both directions are possible indeed, certain features are easier to implement in the WebAssembly on RISC-V direction, while roadblocks might sit in front of you in the RISC-V on WebAssembly direction.</p>
<p>One alternative example is EVM, EVM has been advocating turing complete for years, but the sad truth is that it's close to impossible to build arbitrary complicated algorithsm on EVM: either the coding part is too difficult or gas consumption will be unreasonable. People have to come up with all kinds of hacks so as to introduce latest algorithms on EVM, we can only have reasonable blake2b algorithms in EVM when Istanbul hardfork lands. What about many other algorithms?</p>
<p>All of those reflect our rationale behind the RISC-V choice: we want to find the minimal layer on top of this generation's CPU architecture, and RISC-V is the most transparent model we can expose to the blockchain world while ensuring security and performance. Any different models, such as WebAssembly, EVM, etc., should be one layer on top of the RISC-V model, and can be naturally implemented via the RISC-V model. The other direction, however, might not feel so smooth at all.</p>
<h1>Recap</h1>
<p>Here we demonstrated that you can run non-trivial WebAssembly programs on CKB VM. But we do want to point out this workflow is not without its problems. One gotcha is performance, our preliminary testing shows that the WebAssembly based secp256k1 demo runs 30 times slower than a similar C based implementation compiled directly to CKB VM. After some investigation, we believe this is due to the following problems</p>
<ul>
<li>Due to how memory works in WebAssembly, wasm2c has to first put data segments in the code in plain C array, then when booting, allocate enough memory, then do memcpy to copy the data into the allocated memory. For the secp256k1 example, this means every boot of the program has to copy the 1MB pre-computed multiplication table. Combining with the fact that our RISC-V program now uses newlib, which contains a naive memcpy implementation optimized for code size over speed, this can significantly slow down the program.</li>
<li>While wasm2c can deliver good performance for simpler programs, for a sophisticated and heavily optimized algorithm like secp256k1, the transformation layer could mean that many optimization chances are lost, hence making it slower than a direct implementation compiled directly to RISC-V</li>
</ul>
<p>Luckily, the problems here are totally solvable. The above mentioned workflow is one way we can translate WebAssembly programs to RISC-V programs, but it's absolutely not the only way to achieve that. Like we mentioned above, the transformation layer hinders optimization opportunities, what if we bring in modern compilers to unleash all the possible optimizations here?</p>
<p>There is already <a href="https://github.com/wasmerio/wasmer/tree/master/lib/llvm-backend" target="_blank" rel="noopener noreferrer">progress</a> being done which translates a WebAssembly program via LLVM into native code. The performance obtained here, is really good. Since LLVM 9 <a href="https://riscv.org/2019/09/llvm-9-releases-with-official-risc-v-target-support-asm-goto-clang-9-and-more-vincy-davis-packt-pub/" target="_blank" rel="noopener noreferrer">officially supports</a> RISC-V now, it's perfectly possible to change the code so LLVM generates RISC-V assembly instead of x86_64 assembly. This way we can translate WebAssembly program via LLVM directly into a RISC-V program, enjoying all the advanced optimizations LLVM can performn on our code.</p>
<p>As a result, our current solution documented in this post shows this path is totally possible while achieving good enough performance for many existing cases(e.g., many type scripts can be written in Rust for safety, while the performance is not a big problem), this new LLVM solution can provide far better performance for the same workflow in the future. It's just a matter of time for us to find the time to work on this.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduction to CKB Script Programming 5: Debugging]]></title>
            <link>https://docs.nervos.org/blog/intro-to-ckb-script-programming-5</link>
            <guid>https://docs.nervos.org/blog/intro-to-ckb-script-programming-5</guid>
            <pubDate>Fri, 18 Oct 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Due to the fact that CKB script works at a much lower level than other smart contracts, the debugging story for CKB, has been quite a mysterious one. In this post, we will show how one can debug CKB scripts. As you will find out, debugging a CKB script is not so different from debugging your everyday program.]]></description>
            <content:encoded><![CDATA[<p>Due to the fact that CKB script works at a much lower level than other smart contracts, the debugging story for CKB, has been quite a mysterious one. In this post, we will show how one can debug CKB scripts. As you will find out, debugging a CKB script is not so different from debugging your everyday program.</p>
<p>This post is written based on current CKB Lina mainnet version now.</p>
<p>The first solution to CKB script debugging, works with compiled languages such as C, Rust, etc. Perhaps you are used to writing C programs, and GDB is your best friend. You are wondering if debugging C programs with GDB is possible, and the answer, of course, is: yes, you can definitely debug your CKB script written in C via GDB! Let me show you how.</p>
<p>First we have the same carrot example from my old posts:</p>
<div class="language-c codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-c codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:var(--code-keyword)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">&lt;memory.h&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:var(--code-keyword)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">"ckb_syscalls.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token keyword" style="color:var(--code-keyword)">int</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">main</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:var(--code-keyword)">int</span><span class="token plain"> argc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">char</span><span class="token operator" style="color:var(--text-secondary)">*</span><span class="token plain"> argv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">int</span><span class="token plain"> ret</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token class-name" style="color:rgb(78, 201, 176)">size_t</span><span class="token plain"> index </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token class-name" style="color:rgb(78, 201, 176)">uint64_t</span><span class="token plain"> len </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">unsigned</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">char</span><span class="token plain"> buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">6</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">while</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    len </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">6</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token function" style="color:var(--code-function)">memset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">6</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ret </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">ckb_load_cell_data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">&amp;</span><span class="token plain">len</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> index</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> CKB_SOURCE_OUTPUT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ret </span><span class="token operator" style="color:var(--text-secondary)">==</span><span class="token plain"> CKB_INDEX_OUT_OF_BOUND</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      </span><span class="token keyword" style="color:var(--code-keyword)">break</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">int</span><span class="token plain"> cmp </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">memcmp</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"carrot"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">6</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">cmp</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    index</span><span class="token operator" style="color:var(--text-secondary)">++</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>I've made 2 changes to it:</p>
<ul>
<li>I've updated the script to make it compatible with CKB v0.23.0. In this version, we should be using <code>ckb_load_cell_data</code> to fetch cell data.</li>
<li>I've also introduced a slight bug to the code, so we can later try the debugging workflow. You might noticed it if you are familiar with C, but no need to worry if you missed it, I will explain it later.</li>
</ul>
<p>As usual, let's use our official toolchain to compile it to RISC-V code:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">ls</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">carrot.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">git</span><span class="token plain"> clone https://github.com/nervosnetwork/ckb-system-scripts</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">cp</span><span class="token plain"> ckb-system-scripts/c/ckb_*.h ./</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">ls</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">carrot.c  ckb_consts.h  ckb_syscalls.h  ckb-system-scripts/</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">sudo</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--rm</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-it</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-v</span><span class="token plain"> </span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token variable builtin class-name" style="color:rgb(78, 201, 176)">pwd</span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token plain">:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191012 </span><span class="token function" style="color:var(--code-function)">bash</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@3efa454be9af:/</span><span class="token comment" style="color:var(--code-comment)"># cd /code</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@3efa454be9af:/code</span><span class="token comment" style="color:var(--code-comment)"># riscv64-unknown-elf-gcc carrot.c -g -o carrot</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@3efa454be9af:/code</span><span class="token comment" style="color:var(--code-comment)"># exit</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Notice when I compile the script, I added <code>-g</code> so as to generate debugging information which is quite useful in GDB. For a production script, you would almost always want to strip them out to save previous on-chain space.</p>
<p>Now let's deploy the script to CKB. Have your CKB node running, and fire up to Javascript SDK:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ node</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token maybe-class-name">Welcome</span><span class="token plain"> to </span><span class="token maybe-class-name">Node</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">js</span><span class="token plain"> v20</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token number" style="color:rgb(181, 206, 168)">12.0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token property-access maybe-class-name">Type</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">".help"</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">for</span><span class="token plain"> more information</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> lumos </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">require</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"@ckb-lumos/lumos"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> indexer </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">lumos</span><span class="token class-name punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token class-name" style="color:rgb(78, 201, 176)">Indexer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"https://testnet.ckb.dev/rpc"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> rpc </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">lumos</span><span class="token class-name punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token class-name" style="color:rgb(78, 201, 176)">RPC</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"https://testnet.ckb.dev/rpc"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">config</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">initializeConfig</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">config</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token constant" style="color:var(--code-constant)">TESTNET</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> wallet </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">address</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token string" style="color:rgb(206, 145, 120)">"ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqvwg2cen8extgq8s5puft8vf40px3f599cytcyd8"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">privkey</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x6109170b275a09ad54877b82f7d9930f88cab5717d484fb4741ae9d1dd078cd6"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> wallet2 </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">address</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2prryvze6fhufxkgjx35psh7w70k3hz7c3mtl4d"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">privkey</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0xace08599f3174f4376ae51fdc30950d4f2d731440382bb0aa1b6b0bd3a9728cd"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> data </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> fs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">readFileSync</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"carrot_bug"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">byteLength</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token number" style="color:rgb(181, 206, 168)">19760</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">transfer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain">wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token string" style="color:rgb(206, 145, 120)">"19900"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"00000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">data</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token number" style="color:rgb(181, 206, 168)">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> carrotTxHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With carrot script on blockchain, we can create a transaction to test the carrot script:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> carrotDataHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">utils</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">ckbHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">bytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">bytify</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> carrotTypeScript </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">codeHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> carrotDataHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">hashType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"data"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">args</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">transfer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain">wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token string" style="color:rgb(206, 145, 120)">"100"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"00000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">cellOutput</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">type</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> carrotTypeScript</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">addCellDep</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">outPoint</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">txHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> carrotTxHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">index</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">depType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"code"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token number" style="color:rgb(181, 206, 168)">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> txHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token literal-property property">Uncaught</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token maybe-class-name">ResponseException</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token known-class-name class-name" style="color:rgb(78, 201, 176)">Error</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token string-property property">"code"</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">302</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token string-property property">"message"</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain">"</span><span class="token maybe-class-name">TransactionFailedToVerify</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token maybe-class-name">Verification</span><span class="token plain"> failed </span><span class="token function maybe-class-name" style="color:var(--code-function)">Script</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token known-class-name class-name" style="color:rgb(78, 201, 176)">TransactionScriptError</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">source</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token maybe-class-name">Outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access maybe-class-name">Type</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token literal-property property">cause</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token maybe-class-name">ValidationFailure</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> see error code </span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token plain"> on page</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>If you checked the transaction carefully, you will noticed that none of the output cells has data starting with <code>carrot</code>. However we still run into validation failure, it means our script must have a bug. Previously, you would run out of options here, you might go back to check the code, hoping you can see where it goes wrong. But that is not necessary now, you can just dump the transaction here, and feed it into a standalone CKB debugger to debug it!</p>
<p>First, let's dump the transaction together with its surrounding environment, into a local file:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txJson </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">paramsFormatter</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toRawTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">createTransactionFromSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> fs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">writeFileSync</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'failed-tx.json'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token known-class-name class-name" style="color:rgb(78, 201, 176)">JSON</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">stringify</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txJson</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token keyword null nil" style="color:var(--code-keyword)">null</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You will need <a href="https://github.com/nervosnetwork/ckb-transaction-dumper" target="_blank" rel="noopener noreferrer">ckb-transaction-dumper</a> to convert the <code>failed-tx.json</code> to a dump transaction:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ckb-transaction-dumper </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-t</span><span class="token plain"> failed-tx.json </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> carrot.json</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now let's try <a href="https://github.com/nervosnetwork/ckb-standalone-debugger" target="_blank" rel="noopener noreferrer">ckb-standalone-debugger</a>:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">cargo</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--git</span><span class="token plain"> https://github.com/nervosnetwork/ckb-standalone-debugger ckb-debugger</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ckb-debugger </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--mode</span><span class="token plain"> gdb --gdb-listen </span><span class="token number" style="color:rgb(181, 206, 168)">0.0</span><span class="token plain">.0.0:2000 --tx-file carrot.json --cell-index </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain"> --cell-type output --script-group-type </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">type</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Keep in mind you might need to tweak the path to <code>carrot.json</code> depending on your environment. Now we can try connecting to the debugger via GDB in a differnet terminal:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ sudo docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191012 bash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@66e3b39e0dfd:/# cd /code</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@66e3b39e0dfd:/code# riscv64-unknown-elf-gdb carrot</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">GNU gdb (GDB) 8.3.0.20190516-git</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Copyright (C) 2019 Free Software Foundation, Inc.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">License GPLv3+: GNU GPL version 3 or later &lt;http://gnu.org/licenses/gpl.html&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">This is free software: you are free to change and redistribute it.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">There is NO WARRANTY, to the extent permitted by law.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Type "show copying" and "show warranty" for details.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv64-unknown-elf".</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Type "show configuration" for configuration details.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">For bug reporting instructions, please see:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">&lt;http://www.gnu.org/software/gdb/bugs/&gt;.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Find the GDB manual and other documentation resources online at:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    &lt;http://www.gnu.org/software/gdb/documentation/&gt;.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">For help, type "help".</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Type "apropos word" to search for commands related to "word"...</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Reading symbols from carrot...</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) target remote 192.168.1.230:2000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Remote debugging using 192.168.1.230:2000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">0x00000000000100c6 in _start ()</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Notice <code>192.168.1.230</code>, is the IP address of my workstation in my local network. It's very likely you need to adjust that, since your computer might have a different IP address. Now we can try a normal GDB debugging session:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) b main</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Breakpoint 1 at 0x106b0: file carrot.c, line 6.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Continuing.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Breakpoint 1, main (argc=0, argv=0x400000) at carrot.c:6</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">6         size_t index = 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">7         uint64_t len = 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">11          len = 6;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">12          memset(buffer, 0, 6);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">13          ret = ckb_load_cell_data(buffer, &amp;len, 0, index, CKB_SOURCE_OUTPUT);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">14          if (ret == CKB_INDEX_OUT_OF_BOUND) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">18          int cmp = memcmp(buffer, "carrot", 6);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">19          if (cmp) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) p cmp</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$1 = -99</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) p buffer[0]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$2 = 0 '\000'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(gdb) n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">20            return -1;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Here we can see where it goes wrong: the first byte in <code>buffer</code> has value <code>0</code>, which is different from <code>c</code>, hence our buffer is different from <code>carrot</code>. But instead of jumping to next iteration, the condition <code>if (cmp) {</code> jumps to the true case, where <code>-1</code> is returned, indicating a match to <code>carrot</code>! And the reason to this, is that <code>memcmp</code> would return <code>0</code> when the 2 buffers are equal, and non-zero value when they are not. But instead of testing the return value of <code>memcmp</code> is 0, we directly use it in the <code>if</code> condition, since C would treat any non-zero value as true, <code>-99</code> in this case would be treated as true. This is a typical C mistake for beginners, I hope you will never run into it :)</p>
<p>Now we know the reason, it will be a trivial task to fix the bug in the carrot script, but what you just see here, is that we manage to dump the runtime state of an errored transaction from CKB, then debug it via GDB, which is a common tool in the industry! And your existing workflows and tools on top of GDB can also work here, isn't that beautiful?</p>
<h1>REPL based Development/Debugging</h1>
<p>However, GDB is only one part of the story in modern software development. Dynamic languages have largely taken the landscape, and many programmers are used to REPL baesd development/debugging workflow. This is totally different from GDB in a compiled languages, basically what you get is a running environment, and you can type in any code you want to interact with the environment, getting different results. As we will show here, CKB also has support for this type of development/debugging workflow <!-- -->:P</p>
<p>Here we will use the <a href="https://github.com/nervosnetwork/ckb-duktape" target="_blank" rel="noopener noreferrer">ckb-duktape</a> showcasing a REPL in JavaScript. But keep in mind this is merely a demo showing the workflow, there's nothing preventing you from porting your favorite dynamic languages(whether it's Ruby, Python, Lisp, etc.) to CKB, and start a REPL for that language.</p>
<p>First let's try compiling duktape:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">git</span><span class="token plain"> clone https://github.com/nervosnetwork/ckb-duktape</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">cd</span><span class="token plain"> ckb-duktape</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ </span><span class="token function" style="color:var(--code-function)">sudo</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--rm</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-it</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-v</span><span class="token plain"> </span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token variable builtin class-name" style="color:rgb(78, 201, 176)">pwd</span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token plain">:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191012 </span><span class="token function" style="color:var(--code-function)">bash</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@982d1e906b76:/</span><span class="token comment" style="color:var(--code-comment)"># cd /code</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@982d1e906b76:/code</span><span class="token comment" style="color:var(--code-comment)"># make</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Os</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-DCKB_NO_MMU</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_soft_float</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_float_abi_soft</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Iduktape</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ic</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Wall</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Werror</span><span class="token plain"> c/entry.c </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-c</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/entry.o</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Os</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-DCKB_NO_MMU</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_soft_float</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_float_abi_soft</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Iduktape</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ic</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Wall</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Werror</span><span class="token plain"> duktape/duktape.c </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-c</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/duktape.o</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc build/entry.o build/duktape.o </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/duktape </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-lm</span><span class="token plain"> -Wl,-static -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-s</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Os</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-DCKB_NO_MMU</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_soft_float</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-D__riscv_float_abi_soft</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Iduktape</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Ic</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Wall</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-Werror</span><span class="token plain"> c/repl.c </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-c</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/repl.o</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">riscv64-unknown-elf-gcc build/repl.o build/duktape.o </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> build/repl </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-lm</span><span class="token plain"> -Wl,-static -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-s</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@982d1e906b76:/code</span><span class="token comment" style="color:var(--code-comment)"># exit</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You will need the <code>build/repl</code> binary generated here. Similar to the carrot example, let's first deploy duktape REPL binary on CKB:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ node</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token maybe-class-name">Welcome</span><span class="token plain"> to </span><span class="token maybe-class-name">Node</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">js</span><span class="token plain"> v20</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token number" style="color:rgb(181, 206, 168)">12.0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token property-access maybe-class-name">Type</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">".help"</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">for</span><span class="token plain"> more information</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> lumos </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">require</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"@ckb-lumos/lumos"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> indexer </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">lumos</span><span class="token class-name punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token class-name" style="color:rgb(78, 201, 176)">Indexer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"https://testnet.ckb.dev/rpc"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> rpc </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">lumos</span><span class="token class-name punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token class-name" style="color:rgb(78, 201, 176)">RPC</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"https://testnet.ckb.dev/rpc"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">config</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">initializeConfig</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">config</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token constant" style="color:var(--code-constant)">TESTNET</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> wallet </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">address</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token string" style="color:rgb(206, 145, 120)">"ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqvwg2cen8extgq8s5puft8vf40px3f599cytcyd8"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">privkey</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x6109170b275a09ad54877b82f7d9930f88cab5717d484fb4741ae9d1dd078cd6"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> wallet2 </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">address</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2prryvze6fhufxkgjx35psh7w70k3hz7c3mtl4d"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">privkey</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0xace08599f3174f4376ae51fdc30950d4f2d731440382bb0aa1b6b0bd3a9728cd"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> data </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> fs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">readFileSync</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"./ckb-duktape/build/repl"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">byteLength</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token number" style="color:rgb(181, 206, 168)">306040</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">transfer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain">wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token string" style="color:rgb(206, 145, 120)">"306240"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"00000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">data</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token number" style="color:rgb(181, 206, 168)">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> duktapeReplTxHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We will also need to create a transaction containing the duktape script, I'm building a simpler one, but you are free to include more data so you can play with CKB:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--rm</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-it</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-v</span><span class="token plain"> </span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token variable builtin class-name" style="color:rgb(78, 201, 176)">pwd</span><span class="token variable" style="color:rgb(156, 220, 254)">`</span><span class="token plain">:/code nervos/ckb-riscv-gnu-toolchain:xenial </span><span class="token function" style="color:var(--code-function)">bash</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">cd</span><span class="token plain"> /code</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">echo</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"CKB.debug(</span><span class="token string entity" style="color:rgb(206, 145, 120)">\"</span><span class="token string" style="color:rgb(206, 145, 120)">I'm running in JS</span><span class="token string entity" style="color:rgb(206, 145, 120)">\"</span><span class="token string" style="color:rgb(206, 145, 120)">)"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> test.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> ./build/native_args_assembler </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-f</span><span class="token plain"> test.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">370000000c00000033000000000000001f000000434b422e6465627567282249276d2072756e6e696e6720696e204a5322290a04000000</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> duktapeReplCodeHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">utils</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">ckbHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">bytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">bytify</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"0x"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hex"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> duktapeTypeScript </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">codeHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> duktapeReplCodeHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">hashType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"data"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">args</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x370000000c00000033000000000000001f000000434b422e6465627567282249276d2072756e6e696e6720696e204a5322290a04000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access maybe-class-name" style="color:var(--code-function)">TransactionSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token literal-property property">cellProvider</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> indexer </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">transfer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain">wallet2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token string" style="color:rgb(206, 145, 120)">"150"</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"00000000"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"outputs"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> cell </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">first</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">cellOutput</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">type</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> duktapeTypeScript</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword control-flow" style="color:var(--code-keyword)">return</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">addCellDep</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">outPoint</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">txHash</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> duktapeReplTxHash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token literal-property property">index</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0x0"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token literal-property property">depType</span><span class="token operator" style="color:var(--text-secondary)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"code"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">payFeeByFeeRate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">address</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token number" style="color:rgb(181, 206, 168)">1000</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> txSkeleton </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">commons</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">prepareSigningEntries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signatures </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"signingEntries"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">map</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token parameter">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:var(--text-secondary)">=&gt;</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">hd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">signRecoverable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">entry</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> wallet</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">privkey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toArray</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> signedTx </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sealTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signatures</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">const</span><span class="token plain"> txHash </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:var(--code-keyword)">await</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">sendTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">signedTx</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Let's also dump it to file:</p>
<div class="language-js codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-js codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token keyword" style="color:var(--code-keyword)">let</span><span class="token plain"> txJson </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> rpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">paramsFormatter</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">toRawTransaction</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  lumos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token property-access">helpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">createTransactionFromSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txSkeleton</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">fs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">writeFileSync</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"duktape-tx.json"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token known-class-name class-name" style="color:rgb(78, 201, 176)">JSON</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token method function property-access" style="color:var(--code-function)">stringify</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">txJson</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token keyword null nil" style="color:var(--code-keyword)">null</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">ckb-transaction-dumper </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-t</span><span class="token plain"> duktape-tx.json </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-o</span><span class="token plain"> duktape.json</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Different from last time, we don't need to start GDB, we can start the program directly:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ckb-debugger  --tx-file duktape.json --cell-index </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain"> --cell-type output --script-group-type </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">type</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You will see a <code>duk&gt;</code> prompt for you to enter JS code! Again if you run into errors, check if you need to change to a different type script hash, or use the correct path to <code>duktape.json</code>. We can see normal JS code works here:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> print</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token plain"> + </span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token number" style="color:rgb(181, 206, 168)">3</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> undefined</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">function</span><span class="token plain"> foo</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">a</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">return</span><span class="token plain"> a + </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> undefined</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> foo</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">123</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">124</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>There're also CKB related functions you can use:</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> var </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">hash</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> CKB.load_script_hash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> undefined</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">function</span><span class="token plain"> buf2hex</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">return</span><span class="token plain"> Array.prototype.map.call</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">new Uint8Array</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">, function</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">x</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'00'</span><span class="token plain"> + x.toString</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">16</span><span class="token punctuation" style="color:rgb(212, 212, 212)">))</span><span class="token plain">.slice</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">-2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">.join</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">''</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> undefined</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> buf2hex</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">hash</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> a8b79392c857e29cb283e452f2cd48a8e06c51af64be175e0fe0e2902c482837</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Notice the script hash we get here is exactly the current executing type script hash! This verifies CKB syscalls do work here, we can also try more interesting stuff</p>
<div class="language-bash codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> print</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">CKB.SOURCE.OUTPUT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> undefined</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> print</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">CKB.CELL.CAPACITY</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> undefined</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> capacity_field </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> CKB.load_cell_by_field</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain">, </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain">, CKB.SOURCE.OUTPUT, CKB.CELL.CAPACITY</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">object ArrayBuffer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk</span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> buf2hex</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">capacity_field</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> 00e40b5402000000</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This <code>00e40b5402000000</code> might looks slightly mysterious to you at first, but notice that RISC-V uses little endian, so if we reverse the byte order here, we would get <code>00000002540be400</code>, which is exactly <code>10000000000</code> in decimal. Also keep in mind that in CKB capacity is stored in shannons, so <code>10000000000</code> is exactly <code>100</code> bytes, which is the same amount of coins we want to transfer when we generate the transaction above! Now you can see how you can play with CKB in this duktape environment :)</p>
<h1>Conclusion</h1>
<p>Now we've introduced 2 types of debugging experience in CKB, feel free to play with either one you like(or actually both of them). I can't wait to see all the amazing applications you can build with CKB :)</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduction to CKB Script Programming 6: Type ID]]></title>
            <link>https://docs.nervos.org/blog/intro-to-ckb-script-programming-6</link>
            <guid>https://docs.nervos.org/blog/intro-to-ckb-script-programming-6</guid>
            <pubDate>Mon, 03 Feb 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[You might noticed there's a hashtype field in CKB's Script structure. For simplicity, we've been ignoring that till now. This post will provide an introduction to the hashtype field, and the unique capability it can bring.]]></description>
            <content:encoded><![CDATA[<p>You might noticed there's a <code>hash_type</code> field in CKB's Script structure. For simplicity, we've been ignoring that till now. This post will provide an introduction to the <code>hash_type</code> field, and the unique capability it can bring.</p>
<p>In the blockchain space, there's a pair of issues that everyone has to pick sides:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="upgradability">Upgradability<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-6#upgradability" class="hash-link" aria-label="Direct link to Upgradability" title="Direct link to Upgradability">​</a></h3>
<p>Can I upgrade a smart contract after it's deployed on the blockchain? Suppose a smart contract gets widely adopted, then all of a sudden, someone notices a bug in the smart contract(sadly this will always happen in our industry), can we upgrade the smart contract to a fixed version without affecting all the users?</p>
<p>A different scenario: as technology advances, there might be new algorithms that could be leveraged to build smart contracts that run faster. Can we upgrade existing smart contracts to benefit more users?</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="determinism">Determinism<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-6#determinism" class="hash-link" aria-label="Direct link to Determinism" title="Direct link to Determinism">​</a></h3>
<p>This one has 2 parts:</p>
<ul>
<li>Determinism A: if I pick a smart contract to guard my tokens, will my tokens stay safe(could be unlocked by me and only by me) in the future?</li>
<li>Determinism B: if I sign a transaction now, and send it later, will my transaction still be accepted by the blockchain?</li>
</ul>
<p>Note that a secure blockchain has more deterministic requirements than those mentioned here. I'm only including properties that relate to the discussed problem here.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="conflicts">Conflicts<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-6#conflicts" class="hash-link" aria-label="Direct link to Conflicts" title="Direct link to Conflicts">​</a></h3>
<p>If we think about it, we could find that there're always conflicts between upgradability and determinism:</p>
<ul>
<li>If a smart contract could be upgraded, it might have different behaviors, hence enabling an attacker to unlock a cell, or disabling unlocking from the owner himself/herself.</li>
<li>If a smart contract could be upgraded, an already signed transaction might run into different behaviors, resulting it be rejected by the blockchain.</li>
</ul>
<p>Historically, there is only one side you can pick, and most existing blockchains have picked the side of determinism. The "code is law" idea thus becomes very famous in the blockchain space. But we all know software design is all about tradeoffs. Given certain situation, it might make sense to sacrifice slight determinism, in exchange for the ease of upgradability. For example, a large organization might have special security team monitoring potential vulnerabilities in smart contracts use by them. By granting them the ability to upgrade smart contracts, they have their own control in fixing vulnerabilities instead of waiting on someone. In the meantime, determinism property A won't be an issue for them since they are in charge of their own cells and smart contracts.</p>
<p>So now the question is: can we enable this new possibility in CKB? It turns out we can and this whole mechanism is already deployed in current mainnet CKB! But to understand the whole mechanism in CKB, we have to first take a look at some other ideas that support this mechanism.</p>
<p>NOTE: I'm sure you will ask: does this mean you will sacrifice determinism in CKB? Let me assure you this feature is totally optional in CKB, you can perfectly practice "code is law" principle in CKB like in other blockchains. We are just hoping this unique feature will provide new possibilities for people who really need it.</p>
<h1>Write A Unique Type Script</h1>
<p>Let's first ask a question: how can we create a type script that ensures only one live cell in CKB can have that unique type script? By unique type script, we mean the whole type script structure, including code hash, hash type and args.</p>
<p>Note that this question might seem irrelevant to script upgradability right now, but please bear with me, we will see how it will contribute to the final solution in CKB.</p>
<p>Note if you have seen <a href="https://docs.nervos.org/2019_09_06_introduction_to_ckb_script_programming_udt/">my previous UDT article</a>, you might already realize there is a solution. But if you haven't, I do suggest to take a step back and think about how you can implement such a script on your own. It will be a really good learning experience.</p>
<p>If you are ready, here's the basic workflow of the script:</p>
<ol>
<li>Count how many output cells use current type script, if there's more than one cell with current type script, returns a failure return code;</li>
<li>Count how many input cells use current type script, if there's one input cell with current type script, returns a success return code;</li>
<li>Use CKB syscall to read the first OutPoint in current transaction;</li>
<li>If the OutPoint data read match the <code>args</code> part of current type script, returns a success return code;</li>
<li>Returns a failure return code otherwise.</li>
</ol>
<p>Putting in simple C code, the script would look like following:</p>
<div class="language-c codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-c codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:var(--code-keyword)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">"blockchain.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:var(--code-keyword)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">"ckb_syscalls.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:var(--code-keyword)">define</span><span class="token macro property"> </span><span class="token macro property macro-name">INPUT_SIZE</span><span class="token macro property"> </span><span class="token macro property expression number" style="color:rgb(181, 206, 168)">128</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:var(--code-keyword)">define</span><span class="token macro property"> </span><span class="token macro property macro-name">SCRIPT_SIZE</span><span class="token macro property"> </span><span class="token macro property expression number" style="color:rgb(181, 206, 168)">32768</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token keyword" style="color:var(--code-keyword)">int</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">main</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token class-name" style="color:rgb(78, 201, 176)">uint64_t</span><span class="token plain"> len </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">int</span><span class="token plain"> ret </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">ckb_load_cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token constant" style="color:var(--code-constant)">NULL</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">&amp;</span><span class="token plain">len</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> CKB_SOURCE_GROUP_OUTPUT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ret </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token plain"> CKB_INDEX_OUT_OF_BOUND</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain">  </span><span class="token comment" style="color:var(--code-comment)">/* 1 */</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  len </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ret </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">ckb_load_cell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token constant" style="color:var(--code-constant)">NULL</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">&amp;</span><span class="token plain">len</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> CKB_SOURCE_GROUP_INPUT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ret </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token plain"> CKB_INDEX_OUT_OF_BOUND</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain">  </span><span class="token comment" style="color:var(--code-comment)">/* 2 */</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token comment" style="color:var(--code-comment)">/* 3 */</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">unsigned</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">char</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">INPUT_SIZE</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token class-name" style="color:rgb(78, 201, 176)">uint64_t</span><span class="token plain"> input_len </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> INPUT_SIZE</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ret </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">ckb_load_input</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">&amp;</span><span class="token plain">input_len</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> CKB_SOURCE_INPUT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ret </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token plain"> CKB_SUCCESS</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> ret</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">input_len </span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> INPUT_SIZE</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">100</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">unsigned</span><span class="token plain"> </span><span class="token keyword" style="color:var(--code-keyword)">char</span><span class="token plain"> script</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">SCRIPT_SIZE</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  len </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> SCRIPT_SIZE</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ret </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">ckb_load_script</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">script</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">&amp;</span><span class="token plain">len</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ret </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token plain"> CKB_SUCCESS</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> ret</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">len </span><span class="token operator" style="color:var(--text-secondary)">&gt;</span><span class="token plain"> SCRIPT_SIZE</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">101</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token class-name" style="color:rgb(78, 201, 176)">mol_seg_t</span><span class="token plain"> script_seg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  script_seg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">ptr </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token class-name" style="color:rgb(78, 201, 176)">uint8_t</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">*</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">script</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  script_seg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">size </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> len</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:var(--code-function)">MolReader_Script_verify</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:var(--text-secondary)">&amp;</span><span class="token plain">script_seg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> false</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">!=</span><span class="token plain"> MOL_OK</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">102</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token class-name" style="color:rgb(78, 201, 176)">mol_seg_t</span><span class="token plain"> args_seg </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">MolReader_Script_get_args</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:var(--text-secondary)">&amp;</span><span class="token plain">script_seg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token class-name" style="color:rgb(78, 201, 176)">mol_seg_t</span><span class="token plain"> args_bytes_seg </span><span class="token operator" style="color:var(--text-secondary)">=</span><span class="token plain"> </span><span class="token function" style="color:var(--code-function)">MolReader_Bytes_raw_bytes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:var(--text-secondary)">&amp;</span><span class="token plain">args_seg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">input_len </span><span class="token operator" style="color:var(--text-secondary)">==</span><span class="token plain"> args_bytes_seg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">size</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">&amp;&amp;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:var(--code-function)">memcmp</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">args_bytes_seg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">ptr</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> input_len</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">==</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token comment" style="color:var(--code-comment)">/* 4 */</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  </span><span class="token keyword" style="color:var(--code-keyword)">return</span><span class="token plain"> </span><span class="token operator" style="color:var(--text-secondary)">-</span><span class="token number" style="color:rgb(181, 206, 168)">103</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>As explained in the UDT post, attackers will be prevented in several different directions:</p>
<ol>
<li>If an attacker tries to create a cell with the exactly same type script, there will be 2 cases:
a. A valid transaction will have different OutPoint data in the first input from the type script args;
b. If the user tries to duplicate type script args as the first transaction input, CKB will signal a double-spent error;</li>
<li>If the attacker tries to use a different type script args, it will be a different type script by definition.</li>
</ol>
<p>This way, we can ensure a cell will have unique type script across all live cells in CKB. Considering each script has an associated hash, we will have a cell in CKB with its unique hash, or unique ID.</p>
<h1>Resolving Scripts in CKB Transaction</h1>
<p>Now let's look at how CKB resolves the script to run before the <code>hash type</code> change:</p>
<ul>
<li>CKB extracts <code>code hash</code> value from the script structure to run.</li>
<li>It loops through all dep cells, computes the hash of each dep cell data. If any dep cell data hash matches the specified <code>code hash</code>, CKB uses the data in the found dep cell as the script to run.</li>
<li>If no dep cell has data hash matching specified <code>code hash</code>, CKB results in a validation error.</li>
</ul>
<p>The upgradability problem, in fact lies in the way we test for dep cells. Right now we are testing against data hash, and when a script is upgraded, a different hash will be generated, the matching would fail. That brings a question: can we test for dep cells using a different solution? Is there something that can stay unchanged when the script is changed? Considering the actual script to run lives in a cell, we can rephrase the question in a different way:</p>
<p>Is there something that can stay unchanged when a cell's data get updated?</p>
<p>We can use a script structure! Since lock script is typically used for signature verification, we can use a type script for this problem. A type script can stay perfectly unchanged when a cell's data get changed. Hence we added <code>hash type</code> field to CKB's script structure, and modified the script resolving flow to the following:</p>
<ul>
<li>For each dep cell, we extract the <code>test hash</code> based on <code>hash type</code> value in the script structure:<!-- -->
<ul>
<li>If <code>hash type</code> is <code>data</code>, the dep cell's data hash is used as <code>test hash</code></li>
<li>If <code>hash type</code> is <code>type</code>, the dep cell's type script hash is used as <code>test hash</code></li>
</ul>
</li>
<li>CKB extracts <code>code hash</code> and <code>hash type</code> values from the script structure to run</li>
<li>If CKB finds a dep cell whose <code>test hash</code> matches specified <code>code hash</code>, CKB uses the data in the found dep cell as the scrip to run.</li>
<li>If no dep cell has <code>test hash</code> matching specified <code>code hash</code>, CKB results in a validation error.</li>
</ul>
<p>Notice the <code>hash type</code> used here, is the value belonging to the script to run, not the values of scripts in a dep cell. You could perfectly have 2 inputs in a transaction, one using <code>data</code> as <code>hash type</code>, the other using <code>type</code> as <code>hash type</code>. Either one of them will use its own correct way to locate the correct cell.</p>
<p>This way we have totally conquered determinism property A above, but for property B there will be some subtle affects, we will discuss those in more details below.</p>
<h1>Putting Everything Together</h1>
<p>There's still one problem unsolved, there might still be an attack:</p>
<ul>
<li>A lock script L1 is stored in a cell C1 with type script T1</li>
<li>Alice guards her cells via lock script L1 using <code>hash type</code> as <code>type</code>, by definition, she fills her script structure's <code>code hash</code> field with the hash of type script T1</li>
<li>Bob creates a different cell C2 with a always success lock script L2, and also use the same type script T1</li>
<li>Now Bob can use C2 as a dep cell to unlock Alice's cell. CKB won't be able to distinguish that Alice wants to use C1, while Bob provides C2. Both C1 and C2 use T1 as type script</li>
</ul>
<p>That teaches us a very important lesson: if you build a lock/type script and want people to leverage the upgradability property, you have to make sure to use a type script that is unique and unforgeable.</p>
<p>Luckily, we just solved this problem! In the above we just developed a type script that can provide a unique type script hash in CKB. Combined together, this unique type script and <code>hash type</code> feature in CKB provide a way to upgrade already deployed smart contracts.</p>
<h1>Chicken Egg Problem</h1>
<p>You might have noticed that CKB already implements such a script, named a <a href="https://github.com/nervosnetwork/ckb/blob/2145e4e3adee46670b3c9411c4ac547fc76e3a23/script/src/type_id.rs" target="_blank" rel="noopener noreferrer">type ID</a> script. But unlike the other system scripts, this one is implemented purely in Rust outside of CKB VM. I'm sure you will have this rant: you said CKB VM is flexible, don't you?</p>
<p>I do have made that claim in many different occasions, and in fact I've shown you above a way to implement the type ID logic in C code that could be compiled and run in CKB VM. But the problem here, is that we are at a chicken-egg situation: if we implement the type ID script, should we make it upgradable? If so, what should we put in as its type script? And if it's not upgradable, how can we make sure it's free from bugs and all the other vulnerabilities?</p>
<p>We thought hard on this question, and it really seems the easiest and safest solution, is to implement the type ID script via pure Rust, so we can deal with any potential situations in a more mature and experienced way.</p>
<p>But unlike some other chains which keep provide discounts for builtin smart contracts, we do set a very large cycle cost on the type ID script to discourage the use of the builtin script. At mainnet, it is now set as 1 million cycles. This is much much larger than the same logic implemented on CKB VM, we are hoping one day there will be fully vetted and secure type ID script that everyone will use instead of using this builtin type ID script.</p>
<h1>Trust Issue</h1>
<p>We do want to mention this new feature is not without its drawbacks. You should really understand how it works and the tradeoffs involved before using it. This section tries to discuss all those considerations, but I do want to warn you it might still miss something, and you should use your own judgments.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="determinism-property-a">Determinism Property A<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-6#determinism-property-a" class="hash-link" aria-label="Direct link to Determinism Property A" title="Direct link to Determinism Property A">​</a></h2>
<p>The type ID solution does provide a way to solve property A: when a bug is discovered, it's possible to fix the smart contracts without affecting existing cells using the same smart contracts. But it does require certain considerations:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ownership">Ownership<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-6#ownership" class="hash-link" aria-label="Direct link to Ownership" title="Direct link to Ownership">​</a></h3>
<p>With a type ID solution, people might be able to steal your coin by hacking the cell containing smart contracts you use. Since typical cells are guarded by only one or more signatures, some human errors could cause major problems. Fundamentally, it's a tradeoff situation:</p>
<ol>
<li>For the truly paranoid ones, they might want to stick to the old way of referencing a script via its own hash, not the type script hash of the containing cell. The "code is law" principle is fully enforced here. You will know exactly what can be used to unlock your cell, and it won't change anytime in the future.</li>
<li>For people willing to sacrifice a little bit, they can gain the ability to upgrade existing smart contracts for different benefits. But please do make sure to fully understand the lock script of the cell containing the script you use.</li>
</ol>
<p>For example, if you look at the deployed system scripts in CKB's mainnet, they all use type ID setup, but they all have their lock script's code hash set to all zeros, meaning no one gets to change the lock script easily via a signature. We want to make sure there's a need to change the default lock script, it will be via a fork agreed upon by the whole community, after all IMHO it really is the whole Nervos community that <em>owns</em> CKB <!-- -->:P</p>
<p>There is some initial ideas that you can use to guard the script contained in a cell. For example, in addition to type ID logic, the type script can also contains other logics to validate the actual script contained in its cell. For example, formal analysis methods might be used, or certain test cases can be provided in which the type script run the actual script against. Only when the analysis or the test cases pass, will one be able to change script contained in a cell. Though I must say this is just some priliminary ideas, much research and development work needs to be done to make this a reality.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="availability">Availability<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-6#availability" class="hash-link" aria-label="Direct link to Availability" title="Direct link to Availability">​</a></h3>
<p>A different issue with type ID, is availability of the script. When you have a cell using a script with <code>hash type</code> set as <code>data</code>, you are not worried someone might destroy the used script, you can always redeploy the script on-chain then unlock your cell.</p>
<p>But with a type ID solution, if something bad happens, and the cell with matching type script hash is destroyed, your cell will be locked forever, since your might never be able to build a cell with the same type script hash. There are some methods you can use, such as restricting the ability to destroy a cell with a type ID script but they all just mitigate the problem, not completely solving the problem.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="determinism-property-b">Determinism Property B<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-6#determinism-property-b" class="hash-link" aria-label="Direct link to Determinism Property B" title="Direct link to Determinism Property B">​</a></h2>
<p>We do want to mention that type ID does not provide a solution to property B. When you have a signed transaction, the behavior for this transaction won't be changed with the upgrade of one smart contract.</p>
<p>Though there is way that the type ID solution might affect an already signed transaction: if a transaction uses a script from cell, and the cell gets updated, the transaction will be render invalidated, since the cell referenced in the original OutPoint is already spent. But one could argue with the old referencing solution, this problem might also happen.</p>
<h1>Conclusion</h1>
<p>So that's all I know about type ID at the moment :) It certainly has its drawbacks, but we do believe it can be proved very useful for certain users. For other users, this will be completely optional, and you are perfectly ignoring this feature at all. It's my hope that this new feature rarely seen in other blockchains, can provide a starting point to boost more possibilities.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduction to CKB Script Programming 7: Advanced Duktape Examples]]></title>
            <link>https://docs.nervos.org/blog/intro-to-ckb-script-programming-7</link>
            <guid>https://docs.nervos.org/blog/intro-to-ckb-script-programming-7</guid>
            <pubDate>Fri, 21 Feb 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[I've introduced duktape before, shown how you can run JavaScript code on Nervos CKB. But up to this point, the code I've shown is all single piece of code with very simple logic. What if we need to parse CKB data structures? What if I need external libraries in my script? In this post we will create a duktape-powered CKB script with the following requirements:]]></description>
            <content:encoded><![CDATA[<p>I've introduced duktape before, shown how you can run JavaScript code on Nervos CKB. But up to this point, the code I've shown is all single piece of code with very simple logic. What if we need to parse CKB data structures? What if I need external libraries in my script? In this post we will create a duktape-powered CKB script with the following requirements:</p>
<ul>
<li>External library dependency</li>
<li>Serialization/Deserialization of CKB data structures</li>
<li>Hashing</li>
</ul>
<p>Before continuing on this post, I want to mention that the major work used in this post, is not written by me. The credit really goes to <a href="https://github.com/Keith-CY" target="_blank" rel="noopener noreferrer">one</a> of my colleagues, who spent the effort putting together a very nice <a href="https://github.com/xxuejie/ckb-duktape-template" target="_blank" rel="noopener noreferrer">template</a> we can use here, so we can have a streamlined CKB script development experience via JavaScript &amp; duktape.</p>
<p>This post is written based on current CKB Lina mainnet version now.</p>
<p>In this post, we will write a simple <a href="https://en.bitcoin.it/wiki/Hash_Time_Locked_Contracts" target="_blank" rel="noopener noreferrer">HTLC</a> script in JavaScript. Let me admit that I'm not the world's best teacher, there're many, many people who are better than me in <a href="https://liquality.io/blog/hash-time-locked-contracts-htlcs-explained/~" target="_blank" rel="noopener noreferrer">explaining HTLC</a>. So if you want to know what HTLC is, feel free to check other places first and come back here later.</p>
<p>Now I will assume you know what HTLC is <!-- -->:P<!-- --> The HTLC script we create here, will be unlocked if either one of the following conditions is met:</p>
<ul>
<li>A correct secret string, and a valid signature for public key A are provided;</li>
<li>Certain amount of time is passed, and a valid signature for public key B is provided</li>
</ul>
<p>And there are also several points made in the design of our HTLC script:</p>
<ol>
<li>For simplicity, we will use a trick to do signature verification here: instead of doing signature verification directly in JavaScript, we will rely on a separate cell to provide that a signature of the correct public key is provided. Later in this post we will explain the consequence and consideration regarding signature verifi2ation in JavaScript;</li>
<li>A hash of the correct secret string will be included in <code>args</code> part of the CKB HTLC script structure, so when the script runs, it can run a hashing function on the provided secret string, testing if it is correct;</li>
<li>The amount of time is always set as 100 blocks. To verify 100 blocks has passed, the unlock transaction should include a block header which at least 100 blocks after the cell to unlock is committed on chain.</li>
</ol>
<p>With the design set in stone, let's jump to the implementation now.</p>
<h1>Getting Our Hands Dirty</h1>
<p>While you are certainly welcome to craft the skeleton on your own, a decent <a href="https://github.com/xxuejie/ckb-duktape-template" target="_blank" rel="noopener noreferrer">template</a> has already been prepared by one of my colleagues to save us the time. In this post, we will start from the already built template here:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ export TOP=$(pwd)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/xxuejie/ckb-duktape-template htlc-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd htlc-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm install</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># now you can try building the script first to ensure everything works</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm run build</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now you can use your favorite editor to open <code>src/index.js</code> file in <code>htlc-template</code> repo, the current content of the file looks like this:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat src/index.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const { Molecule } = require('molecule-javascript')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const schema = require('../schema/blockchain-combined.json')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const names = schema.declarations.map(declaration =&gt; declaration.name)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const scriptTypeIndex = names.indexOf('Script')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const scriptType = schema.declarations[scriptTypeIndex]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">// Write your script logic here.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">CKB.debug(scriptType)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We will modify this file to add the logic we need.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="script-debugger-preparation">Script Debugger Preparation<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-7#script-debugger-preparation" class="hash-link" aria-label="Direct link to Script Debugger Preparation" title="Direct link to Script Debugger Preparation">​</a></h2>
<p>To aid script programming, let's put together a debugging environment. The debugging environment will serve 2 purposes:</p>
<ul>
<li>Prepare a complete transaction that can be loaded to CKB debugger;</li>
<li>Create transactions and relay them to CKB</li>
</ul>
<p>Let's first create the environment skeleton:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ mkdir htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm init</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm install --save @nervosnetwork/ckb-sdk-core</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm install --save @nervosnetwork/ckb-sdk-utils</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm install --save molecule-javascript</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm install --save crc32</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now let's create a transaction skeleton for debugger usage:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat skeleton.json</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">{</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "mock_info": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "inputs": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "input": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "previous_output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "tx_hash": "0xa98c57135830e1b91345948df6c4b8870828199a786b26f09f7dec4bc27a73da",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "since": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "capacity": "0x4b9f96b00",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "lock": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "args": "0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947c219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd970dd9a8",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "code_hash": "@DUKTAPE_HASH",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "type": null</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "data": "0x"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "cell_deps": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "cell_dep": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "out_point": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "tx_hash": "0xfcd1b3ddcca92b1e49783769e9bf606112b3f8cf36b96cac05bf44edcf5377e6",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "dep_type": "code"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "capacity": "0x702198d000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "lock": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "args": "0x",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "type": null</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "data": "@SCRIPT_CODE"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "cell_dep": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "out_point": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "tx_hash": "0xfcd1b3ddcca92b1e49783769e9bf606112b3f8cf36b96cac05bf44edcf5377e6",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "index": "0x1"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "dep_type": "code"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "capacity": "0x702198d000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "lock": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "args": "0x",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "type": null</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "data": "@DUKTAPE_CODE"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "header_deps": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "compact_target": "0x1a1e4c2f",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "hash": "0x51d199c4060f703344eab3c9b8794e6c60195ae9093986c35dba7c3486224409",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "number": "0xd8fc4",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "parent_hash": "0xc02e01eb57b205c6618c9870667ed90e13adb7e9a7ae00e7a780067a6bfa6a7b",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "nonce": "0xca8c7caa8100003400231b4f9d6e0300",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "timestamp": "0x17061eab69e",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "transactions_root": "0xffb0863f4ae1f3026ba99b2458de2fa69881f7508599e2ff1ee51a54c88b5f88",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "uncles_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "version": "0x0",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "epoch": "0x53f00fa000232",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "dao": "0x4bfe53a5a9bb9a30c88898b9dfe22300a58f2bafed47680000d3b9f5b6630107"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "tx": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "version": "0x0",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "cell_deps": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "out_point": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "tx_hash": "0xfcd1b3ddcca92b1e49783769e9bf606112b3f8cf36b96cac05bf44edcf5377e6",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "dep_type": "code"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "out_point": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "tx_hash": "0xfcd1b3ddcca92b1e49783769e9bf606112b3f8cf36b96cac05bf44edcf5377e6",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "index": "0x1"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "dep_type": "code"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "header_deps": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      "0x51d199c4060f703344eab3c9b8794e6c60195ae9093986c35dba7c3486224409"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "inputs": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "previous_output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "tx_hash": "0xa98c57135830e1b91345948df6c4b8870828199a786b26f09f7dec4bc27a73da",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "since": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "outputs": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "capacity": "0x0",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "lock": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "args": "0x",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "type": null</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "witnesses": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      "0x210000000c0000001d0000000d0000006920616d20612073656372657400000000"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "outputs_data": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      "0x"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You might notice that the skeleton skips dep cell data part, this is because as we develop the HTLC script, we might need to insert different contents in the skeleton. Hence a runner here is needed to prepare the skeleton to a full transaction, then run it via CKB debugger:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat runner.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#!/usr/bin/env node</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const { Molecule } = require('molecule-javascript')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const schema = require('../htlc-template/schema/blockchain-combined.json')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const utils = require("@nervosnetwork/ckb-sdk-utils")</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const process = require('process')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const fs = require('fs')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function blake2b(buffer) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return utils.blake2b(32, null, null, utils.PERSONAL).update(buffer).digest('binary')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">if (process.argv.length !== 4) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  console.log(`Usage: ${process.argv[1]} &lt;duktape load0 binary&gt; &lt;js script&gt;`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  process.exit(1)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const duktape_binary = fs.readFileSync(process.argv[2])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const duktape_hash = blake2b(duktape_binary)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const js_script = fs.readFileSync(process.argv[3])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const data = fs.readFileSync('skeleton.json', 'utf8').</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      replace("@DUKTAPE_HASH", utils.bytesToHex(duktape_hash)).</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      replace("@SCRIPT_CODE", utils.bytesToHex(js_script)).</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      replace("@DUKTAPE_CODE", utils.bytesToHex(duktape_binary))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">fs.writeFileSync('tx.json', data)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const resolved_tx = JSON.parse(data)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const json_lock_script = resolved_tx.mock_info.inputs[0].output.lock</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const lock_script = {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  codeHash: json_lock_script.code_hash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  hashType: json_lock_script.hash_type,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  args: json_lock_script.args</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const lock_script_hash = blake2b(utils.hexToBytes(utils.serializeScript(lock_script)))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">console.log(`../ckb-standalone-debugger/bins/target/release/ckb-debugger -g lock -h ${utils.bytesToHex(lock_script_hash)} -t tx.json`)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We need to compile duktape here:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone --recursive https://github.com/xxuejie/ckb-duktape</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ckb-duktape</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ sudo docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191209 bash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@18d4b1952624:/# cd /code</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@18d4b1952624:/code# make</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@18d4b1952624:/code# exit</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>And also CKB debugger:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone --recursive https://github.com/xxuejie/ckb-standalone-debugger</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ckb-standalone-debugger/bins</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cargo build --release</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now you can try running generated script:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ chmod +x runner.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug `./runner.js ../ckb-duktape/build/load0 ../htlc-template/build/duktape.js`</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x8209891745eb858abd6f5e53c99b4f101bca221bd150a2ece58a389b7b4f8fa7) DEBUG OUTPUT: [object Object]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This will prepare the transaction to run from duktape binary and JS script, then run it via CKB debugger, debug outputs and final results will be printed to stdout.</p>
<p>Or if you find a REPL more helpful, you can use the following line to execute the script and then start a REPL:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug `./runner.js ../ckb-duktape/build/repl0 ../htlc-template/build/duktape.js`</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duk&gt;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With the debugger ready, let's now start to implement the HTLC script.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="custom-arguments">Custom Arguments<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-7#custom-arguments" class="hash-link" aria-label="Direct link to Custom Arguments" title="Direct link to Custom Arguments">​</a></h2>
<p>CKB provides 2 places that we can use to hold arguments to scripts running on CKB:</p>
<ul>
<li><code>args</code> field in <code>Script</code> structure</li>
<li><code>witnesses</code> field in <code>Transaction</code> structure</li>
</ul>
<p>The difference between them, is that <code>args</code> field is used to hold arguments that remains the same for all usage of the same script, while <code>witnesses</code> field is used for temporary arguments that are used in one-time transaction validation. One example here is: for a script that does signature verification, <code>args</code> field is typically used to store public key hash, while <code>witnesses</code> field is used to hold valid signature.</p>
<p>For maximum flexibility, both <code>args</code> field and each item in the <code>witnesses</code> array field are just plain raw bytes. It's up to dapp developers to design the actual format of data they want to hold. In our HTLC script, we will use <a href="https://github.com/nervosnetwork/molecule" target="_blank" rel="noopener noreferrer">molecule</a> serialization format. Molecule is widely used in CKB. If you want to interact with CKB, such as reading certain cell/script used in the current transaction, you will need to deal with molecule format. Now this is a perfect opportunity to explain how one can interact with CKB via molecule in great details, hence we will implement the custom structure used by <code>args</code> and <code>witness</code> in molecule format. Though you are free to use any serialization format in your own scripts.</p>
<p>Let's first create a file with the 2 needed data structure:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat htlc.mol</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">array Uint32 [byte; 4];</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">array Byte32 [byte; 32];</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">vector Bytes &lt;byte&gt;;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">struct HtlcArgs {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  a: Byte32,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  b: Byte32,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  hash: Uint32,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">table HtlcWitness {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  s: Bytes,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  i: Uint32,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>For more information on molecule, please refer to the <a href="https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0008-serialization/0008-serialization.md" target="_blank" rel="noopener noreferrer">RFC</a>. Here we are defining 2 structures with following requirements:</p>
<ul>
<li><code>HtlcArgs</code> requires 2 32-byte long raw bytes for storing both public keys(later we shall the HTLC script here actually generalizes a bit from this design), and a single 32-bit integer value for storing hash. For simplicity, our HTLC will use CRC32 as the hash function, but in a production setting, this is far from a secure solution, and you should definitely use a proper secure hash function for this;</li>
<li><code>HtlcWitness</code> has 2 optional(denoted by the <code>table</code> construct) arguments: it contains either a variable length string containing the secret string for HTLC, or a 32-bit integer value denoting the header to check for 100 block rule.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="deserializing-in-molecule">Deserializing in Molecule<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-7#deserializing-in-molecule" class="hash-link" aria-label="Direct link to Deserializing in Molecule" title="Direct link to Deserializing in Molecule">​</a></h2>
<p>With the molecule definition in place for the custom data structure, we need to first convert them into a format that can be consumed by the JavaScript implementation of molecule:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cargo install moleculec</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ moleculec --language - --format json --schema-file htlc.mol &gt; src/htlc.json</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npx moleculec-js -ns src/htlc.json &gt; src/htlc-combined.json</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now we can fill in the code that loads current Script, and parses the serialized args into a valid structure:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat src/index.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const { Molecule } = require('molecule-javascript')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const schema = require('../schema/blockchain-combined.json')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const names = schema.declarations.map(declaration =&gt; declaration.name)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const scriptTypeIndex = names.indexOf('Script')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const scriptType = new Molecule(schema.declarations[scriptTypeIndex])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">// Write your script logic here.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const customSchema = require('./htlc-combined.json')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const customNames = customSchema.declarations.map(d =&gt; d.name)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgsIndex = customNames.indexOf('HtlcArgs')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgsType = new Molecule(customSchema.declarations[htlcArgsIndex])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function bytesToHex(b) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return "0x" + Array.prototype.map.call(</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    new Uint8Array(b),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    function(x) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      return ('00' + x.toString(16)).slice(-2)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ).join('')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function hexStringArrayToHexString(a) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  let s = "0x";</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (let i = 0; i &lt; a.length; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    s = s + a[i].substr(2)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return s</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const current_script = scriptType.deserialize(bytesToHex(CKB.load_script(0)))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const args = hexStringArrayToHexString(current_script[2][1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgs = htlcArgsType.deserialize(args)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">CKB.debug(`a: ${hexStringArrayToHexString(htlcArgs[0][1])}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">CKB.debug(`b: ${hexStringArrayToHexString(htlcArgs[1][1])}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">CKB.debug(`c: ${hexStringArrayToHexString(htlcArgs[2][1])}`)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>If we ignore the bookkeeping code for a sec, what matters here, is that we first use CKB syscall to load script, parse script structure, then get args:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const current_script = scriptType.deserialize(bytesToHex(CKB.load_script(0)))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const args = hexStringArrayToHexString(current_script[2][1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgs = htlcArgsType.deserialize(args)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We assume script args contain serialized HtlcArgs structure defined above, then we apply similar method to exact them:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgs = htlcArgsType.deserialize(args)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>I have already provided some meaningful data in the skeleton, so if we try to execute the script:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm run build</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug `./runner.js ../ckb-duktape/build/load0 ../htlc-template/build/duktape.js`</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x35ab3d033e66c426573ed4b7ce816e248cb042d908fd8cfe7bba27acb37fb108) DEBUG OUTPUT: a: 0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x35ab3d033e66c426573ed4b7ce816e248cb042d908fd8cfe7bba27acb37fb108) DEBUG OUTPUT: b: 0xc219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x35ab3d033e66c426573ed4b7ce816e248cb042d908fd8cfe7bba27acb37fb108) DEBUG OUTPUT: c: 0x970dd9a8</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We can find parsed results from debug logs.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="adding-new-library">Adding new library<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-7#adding-new-library" class="hash-link" aria-label="Direct link to Adding new library" title="Direct link to Adding new library">​</a></h2>
<p>Another thing I want to show here, is that you can include many libraries out there already on npm, assuming:</p>
<ul>
<li>There's a ES5 version(or you can actually adjust the webpack pipeline yourself to add polyfills) of the library;</li>
<li>It is implemented purely in JavaScript without native code</li>
</ul>
<p>In the HTLC script, I'm gonna add <a href="https://github.com/beatgammit/crc32" target="_blank" rel="noopener noreferrer">crc32</a>, and use crc32 to calculate secret string hash. I want to mention again here that CRC32 is never a secure hash function. We pick it out of simplicity, not security. In a production setting, you should really use a real secure hash function probably implemented natively rather than using JavaScript. But for now, crc32 is quite perfect for our tutorial <!-- -->:P</p>
<p>Let's include crc32 in our template, and write some debugging code to test it:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm install --save crc32</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat src/index.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const { Molecule } = require('molecule-javascript')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const schema = require('../schema/blockchain-combined.json')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const names = schema.declarations.map(declaration =&gt; declaration.name)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const scriptTypeIndex = names.indexOf('Script')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const scriptType = new Molecule(schema.declarations[scriptTypeIndex])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">// Write your script logic here.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const customSchema = require('./htlc-combined.json')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const customNames = customSchema.declarations.map(d =&gt; d.name)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgsIndex = customNames.indexOf('HtlcArgs')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgsType = new Molecule(customSchema.declarations[htlcArgsIndex])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function bytesToHex(b) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return "0x" + Array.prototype.map.call(</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    new Uint8Array(b),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    function(x) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      return ('00' + x.toString(16)).slice(-2)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ).join('')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function hexStringArrayToHexString(a) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  let s = "0x";</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (let i = 0; i &lt; a.length; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    s = s + a[i].substr(2)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return s</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const current_script = scriptType.deserialize(bytesToHex(CKB.load_script(0)))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const args = hexStringArrayToHexString(current_script[2][1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgs = htlcArgsType.deserialize(args)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">CKB.debug(`c: ${hexStringArrayToHexString(htlcArgs[2][1])}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const crc32 = require('crc32')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">CKB.debug(crc32('i am a secret'))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm run build</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug `./runner.js ../ckb-duktape/build/load0 ../htlc-template/build/duktape.js`</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x35ab3d033e66c426573ed4b7ce816e248cb042d908fd8cfe7bba27acb37fb108) DEBUG OUTPUT: c: 0x970dd9a8</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x35ab3d033e66c426573ed4b7ce816e248cb042d908fd8cfe7bba27acb37fb108) DEBUG OUTPUT: 970dd9a8</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You might noticed that the 2 values we printed here are exactly the same! That's because <code>i am a secret</code> is exactly the secret string I'm picking when preparing the skeleton.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="piecing-the-contract-together">Piecing the Contract Together<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-7#piecing-the-contract-together" class="hash-link" aria-label="Direct link to Piecing the Contract Together" title="Direct link to Piecing the Contract Together">​</a></h2>
<p>With all the libraries and required knowledge in place, we can now finish implementing the script:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat src/index.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const { Molecule } = require('molecule-javascript')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const schema = require('../schema/blockchain-combined.json')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const names = schema.declarations.map(declaration =&gt; declaration.name)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const scriptTypeIndex = names.indexOf('Script')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const scriptType = new Molecule(schema.declarations[scriptTypeIndex])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">// Write your script logic here.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const customSchema = require('./htlc-combined.json')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const customNames = customSchema.declarations.map(d =&gt; d.name)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgsIndex = customNames.indexOf('HtlcArgs')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgsType = new Molecule(customSchema.declarations[htlcArgsIndex])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function bytesToHex(b) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return "0x" + Array.prototype.map.call(</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    new Uint8Array(b),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    function(x) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      return ('00' + x.toString(16)).slice(-2)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ).join('')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function hexStringArrayToString(a) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  let s = "";</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (let i = 0; i &lt; a.length; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    s = s + String.fromCharCode(parseInt(a[i]))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return s</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function hexStringArrayToHexString(a) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  let s = "0x";</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (let i = 0; i &lt; a.length; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    s = s + a[i].substr(2)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return s</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function parseLittleEndianHexStringArray(a) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  let v = 0</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const l = a.length</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (let i = 0; i &lt; l; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    v = (v &lt;&lt; 8) | parseInt(a[l - i - 1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return v</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const current_script = scriptType.deserialize(bytesToHex(CKB.load_script(0)))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const args = hexStringArrayToHexString(current_script[2][1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgs = htlcArgsType.deserialize(args)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">// Load and parse witness data using the same method as above</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcWitnessIndex = customNames.indexOf('HtlcWitness')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcWitnessType = new Molecule(customSchema.declarations[htlcWitnessIndex])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const rawWitness = CKB.load_witness(0, 0, CKB.SOURCE.GROUP_INPUT)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">if (typeof rawWitness === 'number') {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  throw new Error(`Invalid response when loading witness: ${rawWitness}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcWitness = htlcWitnessType.deserialize(bytesToHex(rawWitness))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">let lockHashToMatch;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">if (htlcWitness[0][1].length &gt; 0) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  // Test secret string hash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const crc32 = require('crc32')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const hash = '0x' + crc32(hexStringArrayToString(htlcWitness[0][1]))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (hash !== hexStringArrayToHexString(htlcArgs[2][1])) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    throw new Error(`Invalid secret string!`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  lockHashToMatch = hexStringArrayToHexString(htlcArgs[0][1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">} else {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  // Test header block</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const headerTypeIndex = names.indexOf('Header')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const headerType = new Molecule(schema.declarations[headerTypeIndex])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  // Load header for current input first</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const rawInputHeader = CKB.load_header(0, 0, CKB.SOURCE.GROUP_INPUT)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (typeof rawWitness === 'number') {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    throw new Error(`Invalid response when loading input header: ${rawInputHeader}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const inputHeader = headerType.deserialize(bytesToHex(rawInputHeader))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const inputHeaderNumber = parseLittleEndianHexStringArray(inputHeader[0][1][3][1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const targetHeaderIndex = parseLittleEndianHexStringArray(htlcWitness[1][1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const rawTargetHeader = CKB.load_header(0, targetHeaderIndex,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                                          CKB.SOURCE.HEADER_DEP)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (typeof rawTargetHeader === 'number') {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    throw new Error(`Invalid response when loading target header: ${rawTargetHeader}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const targetHeader = headerType.deserialize(bytesToHex(rawTargetHeader))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const targetHeaderNumber = parseLittleEndianHexStringArray(targetHeader[0][1][3][1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (targetHeaderNumber &lt; inputHeaderNumber + 100) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    throw new Error(`Timeout period has not reached!`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  lockHashToMatch = hexStringArrayToHexString(htlcArgs[1][1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">// Now we know which lock hash to test against, we look for an input cell</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">// with the specified lock hash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">let i = 0</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">while (true) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const rawHash = CKB.load_cell_by_field(0, i, CKB.SOURCE.INPUT, CKB.CELL.LOCK_HASH)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (rawHash == CKB.CODE.INDEX_OUT_OF_BOUND) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    throw new Error(`Cannot find input cell using lock hash ${lockHashToMatch}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (typeof rawHash === 'number') {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    throw new Error(`Invalid response when loading input cell: ${rawHash}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (bytesToHex(rawHash) == lockHashToMatch) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    break</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  i += 1</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>It uses similar techniques as shown above to parse witness and block headers, which are also in molecule format.</p>
<p>There's one trick worth mentioning: in the design of HTLC script, I mentioned that the script needs to do signature verification for a given public key. The actual implemention we have here, generalizes slightly from this design:</p>
<ol>
<li>Instead of test a given public key, we are testing for the whole lock script hash. While this certainly satisfies our requirement, it provides more possibilities: if everyone is using the default secp256k1 lock script, different public keys will be reflected in script args part, resulting in differnet lock scripts. So testing lock scripts can certainly ensure different public keys are using. On the other hand, not everyone might be using the default secp256k1 lock script, so testing lock script hash directly, can enable more flexibilities in the HTLC script usage.</li>
<li>While one can certainly embeds the signature verification logic within the HTLC script, we opt for a different and simpler solution here: we just test that one of the input cell has the specified lock script. Per CKB's validation rules, if the transaction is accepted by the blockchain, each input cells' lock script must pass validation, which means the lock script specified in the HTLC script will also pass validation, satisfying the validation rules of HTLC script.</li>
</ol>
<p>To summarize a bit, we are actually showing 2 patterns that can be handy when desining dapps on CKB:</p>
<ol>
<li>Instead of testing signature verification for a public key, one can test for the validation of a lock script to enable flexibilities.</li>
<li>Instead of duplicating a different lock script, one can check for the existence of an input cell using the same lock, and delegate the validation work to the input cell's lock script.</li>
</ol>
<p>Fundamentally, it depends on your use case to see if those patterns can apply. Later we might also build real composable scripts via dynamic linking to supplyment pattern 2. But having those in your armory might turn out to be useful when your design can be simply by them.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="always-audit-your-script">Always Audit Your Script<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-7#always-audit-your-script" class="hash-link" aria-label="Direct link to Always Audit Your Script" title="Direct link to Always Audit Your Script">​</a></h2>
<p>One final note here, is that you should always remember to audit the script before deploying it and putting real tokens in it. The above HTLC script is primarily for introductory purposes. I can easily recognize a few vulnerabilities in them. You should never use it directly on CKB mainnet. However, it does provide a quite interesting exercise, so if you are interested, feel free to read the script and see if you can spot the vulnerabilities yourself <!-- -->:P</p>
<h1>Running HTLC Script on Chain</h1>
<p>There're 2 parts in testing a CKB script: previously, we were using a off-chain debugger environment to test the script for faster iteration. Now that we have a complete HTLC script, we should also deploy it on a dev chain and test the whole workflow. After all any blockchain smart contracts cannot live alone, they have to have a surrounding environments that help prepare the transaction and invoke them on chain. This is more the case for CKB, since CKB uses a separated validator-generator model.</p>
<p>To test our HTLC script on chain, we are gonna reuse our <code>htlc-runner</code> environment here, and write a few more node executables that can deploy and test the HTLC script on chain. The first executable we will write, is an executable to deploy duktape binary as well as our HTLC script on chain:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat deploy_scripts.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#!/usr/bin/env node</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const CKB = require("@nervosnetwork/ckb-sdk-core").default</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const utils = require("@nervosnetwork/ckb-sdk-utils")</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const process = require('process')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const fs = require('fs')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">if (process.argv.length !== 6) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  console.log(`Usage: ${process.argv[1]} &lt;duktape load0 binary&gt; &lt;js script&gt; &lt;private key&gt; &lt;node URL&gt;`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  process.exit(1)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const duktapeBinary = fs.readFileSync(process.argv[2])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const jsScript = fs.readFileSync(process.argv[3])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const privateKey = process.argv[4]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const nodeUrl = process.argv[5]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const run = async () =&gt; {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const ckb = new CKB(nodeUrl)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const secp256k1Dep = await ckb.loadSecp256k1Dep()</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const publicKey = ckb.utils.privateKeyToPublicKey(privateKey)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const publicKeyHash = `0x${ckb.utils.blake160(publicKey, 'hex')}`</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const lockScript = {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    hashType: secp256k1Dep.hashType,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    codeHash: secp256k1Dep.codeHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    args: publicKeyHash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const lockHash = ckb.utils.scriptToHash(lockScript)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const unspentCells = await ckb.loadCells({</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    lockHash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  })</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const totalCapacity = unspentCells.reduce((sum, cell) =&gt; sum + BigInt(cell.capacity), 0n)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  // For simplicity, we will just use 1 CKB as fee. On a real setup you</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  // might not want to do this.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const fee = 100000000n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const duktapeBinaryCapacity = BigInt(duktapeBinary.length) * 100000000n + 4100000000n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const jsScriptCapacity = BigInt(jsScript.length) * 100000000n + 4100000000n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const outputs = [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      lock: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        codeHash: '0x0000000000000000000000000000000000000000000000000000000000000000',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        hashType: 'data',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        args: '0x'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      type: null,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      capacity: '0x' + duktapeBinaryCapacity.toString(16)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      lock: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        codeHash: '0x0000000000000000000000000000000000000000000000000000000000000000',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        hashType: 'data',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        args: '0x'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      type: null,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      capacity: '0x' + jsScriptCapacity.toString(16)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      lock: lockScript,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      type: null,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      capacity: '0x' + (totalCapacity - jsScriptCapacity - duktapeBinaryCapacity - fee).toString(16)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const outputsData = [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    utils.bytesToHex(duktapeBinary),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    utils.bytesToHex(jsScript),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    '0x'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const transaction = {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    version: '0x0',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    cellDeps: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        outPoint: secp256k1Dep.outPoint,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        depType: 'depGroup'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    headerDeps: [],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    inputs: unspentCells.map(cell =&gt; ({</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      previousOutput: cell.outPoint,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      since: '0x0'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    })),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    outputs,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    witnesses: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        lock: '',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        inputType: '',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        outputType: ''</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    outputsData</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const signedTransaction = ckb.signTransaction(privateKey)(transaction)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const txHash = await ckb.rpc.sendTransaction(signedTransaction, 'passthrough')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  console.log(`Transaction hash: ${txHash}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  fs.writeFileSync('deploy_scripts_result.txt', txHash)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">run()</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The second executable creates a cell using HTLC script as lock:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat create_htlc_cell.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#!/usr/bin/env node</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const { Molecule } = require('molecule-javascript')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const crc32 = require('crc32')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const CKB = require("@nervosnetwork/ckb-sdk-core").default</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const utils = require("@nervosnetwork/ckb-sdk-utils")</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const process = require('process')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const fs = require('fs')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function blake2b(buffer) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return utils.blake2b(32, null, null, utils.PERSONAL).update(buffer).digest('binary')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">if (process.argv.length !== 8) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  console.log(`Usage: ${process.argv[1]} &lt;duktape load0 binary&gt; &lt;deployed tx hash&gt; &lt;private key&gt; &lt;node URL&gt; &lt;lock hash A&gt; &lt;lock hash B&gt;`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  process.exit(1)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const duktapeBinary = fs.readFileSync(process.argv[2])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const duktapeHash = blake2b(duktapeBinary)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const deployedTxHash = process.argv[3]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const privateKey = process.argv[4]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const nodeUrl = process.argv[5]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const lockHashA = process.argv[6]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const lockHashB = process.argv[7]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function hexStringToHexStringArray(s) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  let arr = []</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (let i = 2; i &lt; s.length; i += 2) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    arr.push('0x' + s.substr(i, 2))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return arr</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const run = async () =&gt; {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const ckb = new CKB(nodeUrl)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const secp256k1Dep = await ckb.loadSecp256k1Dep()</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const publicKey = ckb.utils.privateKeyToPublicKey(privateKey)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const publicKeyHash = `0x${ckb.utils.blake160(publicKey, 'hex')}`</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const lockScript = {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    hashType: secp256k1Dep.hashType,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    codeHash: secp256k1Dep.codeHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    args: publicKeyHash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const lockHash = ckb.utils.scriptToHash(lockScript)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const unspentCells = await ckb.loadCells({</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    lockHash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  })</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const totalCapacity = unspentCells.reduce((sum, cell) =&gt; sum + BigInt(cell.capacity), 0n)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  // For simplicity, we will just use 1 CKB as fee. On a real setup you</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  // might not want to do this.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const fee = 100000000n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const htlcCellCapacity = 200000000000n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const customSchema = JSON.parse(fs.readFileSync('../htlc-template/src/htlc-combined.json'))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const htlcArgsType = new Molecule(</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    customSchema.declarations.find(d =&gt; d.name == "HtlcArgs"))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const htlcScriptArgs = htlcArgsType.serialize([</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ['a', hexStringToHexStringArray(lockHashA)],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ['b', hexStringToHexStringArray(lockHashB)],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ['hash', hexStringToHexStringArray('0x' + crc32('i am a secret'))]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const transaction = {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    version: '0x0',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    cellDeps: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        outPoint: secp256k1Dep.outPoint,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        depType: 'depGroup'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    headerDeps: [],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    inputs: unspentCells.map(cell =&gt; ({</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      previousOutput: cell.outPoint,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      since: '0x0'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    })),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    outputs: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        lock: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          codeHash: utils.bytesToHex(duktapeHash),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          hashType: 'data',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          args: htlcScriptArgs</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        type: null,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        capacity: '0x' + htlcCellCapacity.toString(16)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        lock: lockScript,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        type: null,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        capacity: '0x' + (totalCapacity - fee - htlcCellCapacity).toString(16)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    witnesses: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        lock: '',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        inputType: '',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        outputType: ''</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    outputsData: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      '0x',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      '0x'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const signedTransaction = ckb.signTransaction(privateKey)(transaction)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const txHash = await ckb.rpc.sendTransaction(signedTransaction, 'passthrough')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  console.log(`Transaction hash: ${txHash}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  fs.writeFileSync('create_htlc_cell_result.txt', txHash)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">run()</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>One thing worth mentioning, is that this executable shows how we can serialize a molecule formatted data structure:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">// ...</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function hexStringToHexStringArray(s) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  let arr = []</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (let i = 2; i &lt; s.length; i += 2) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    arr.push('0x' + s.substr(i, 2))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return arr</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">// ...</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const customSchema = JSON.parse(fs.readFileSync('../htlc-template/src/htlc-combined.json'))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcArgsType = new Molecule(</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  customSchema.declarations.find(d =&gt; d.name == "HtlcArgs"))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcScriptArgs = htlcArgsType.serialize([</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ['a', hexStringToHexStringArray(lockHashA)],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ['b', hexStringToHexStringArray(lockHashB)],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ['hash', hexStringToHexStringArray('0x' + crc32('i am a secret'))]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">// ...</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>And now a executable that tries to unlock HTLC guarded cell by providing secret string:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat unlock_via_secret_string.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#!/usr/bin/env node</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const { Molecule } = require('molecule-javascript')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const crc32 = require('crc32')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const CKB = require("@nervosnetwork/ckb-sdk-core").default</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const utils = require("@nervosnetwork/ckb-sdk-utils")</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const process = require('process')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const fs = require('fs')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function blake2b(buffer) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return utils.blake2b(32, null, null, utils.PERSONAL).update(buffer).digest('binary')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">if (process.argv.length !== 8) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  console.log(`Usage: ${process.argv[1]} &lt;deployed tx hash&gt; &lt;htlc cell tx hash&gt; &lt;private key&gt; &lt;node URL&gt; &lt;secret string&gt; &lt;dry run&gt;`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  process.exit(1)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const deployedTxHash = process.argv[2]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcCellTxHash = process.argv[3]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const privateKey = process.argv[4]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const nodeUrl = process.argv[5]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const secretString = process.argv[6]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const dryrun = process.argv[7] === 'true'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function stringToHexStringArray(s) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  let a = []</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (let i = 0; i &lt; s.length; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    a.push('0x' + ('00' + s.charCodeAt(i).toString(16)).slice(-2))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return a</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const run = async () =&gt; {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const ckb = new CKB(nodeUrl)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const secp256k1Dep = await ckb.loadSecp256k1Dep()</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const publicKey = ckb.utils.privateKeyToPublicKey(privateKey)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const publicKeyHash = `0x${ckb.utils.blake160(publicKey, 'hex')}`</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const lockScript = {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    hashType: secp256k1Dep.hashType,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    codeHash: secp256k1Dep.codeHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    args: publicKeyHash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const lockHash = ckb.utils.scriptToHash(lockScript)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const unspentCells = await ckb.loadCells({</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    lockHash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  })</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const totalCapacity = unspentCells.reduce((sum, cell) =&gt; sum + BigInt(cell.capacity), 0n)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  // For simplicity, we will just use 1 CKB as fee. On a real setup you</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  // might not want to do this.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const fee = 100000000n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const htlcCellCapacity = 200000000000n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const customSchema = JSON.parse(fs.readFileSync('../htlc-template/src/htlc-combined.json'))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const htlcWitnessType = new Molecule(</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    customSchema.declarations.find(d =&gt; d.name == "HtlcWitness"))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const htlcWitness = htlcWitnessType.serialize([</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ['s', stringToHexStringArray(secretString)],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ['i', ['0x0', '0x0', '0x0', '0x0']]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const transaction = {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    version: '0x0',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    cellDeps: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      // Due to the requirement of load0 duktape binary, JavaScript source cell</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      // should be the first one in cell deps</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        outPoint: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          txHash: deployedTxHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          index: "0x1"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        depType: 'code'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        outPoint: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          txHash: deployedTxHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          index: "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        depType: 'code'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        outPoint: secp256k1Dep.outPoint,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        depType: 'depGroup'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    headerDeps: [],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    inputs: unspentCells.map(cell =&gt; ({</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      previousOutput: cell.outPoint,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      since: '0x0'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    })),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    outputs: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        lock: lockScript,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        type: null,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        capacity: '0x' + (totalCapacity + htlcCellCapacity - fee).toString(16)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    witnesses: unspentCells.map(_cell =&gt; '0x'),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    outputsData: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      '0x',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      '0x'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  transaction.inputs.push({</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    previousOutput: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      txHash: htlcCellTxHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      index: "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    since: '0x0'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  })</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  transaction.witnesses[0] = {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    lock: '',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    inputType: '',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    outputType: ''</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const signedTransaction = ckb.signTransaction(privateKey)(transaction)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  signedTransaction.witnesses.push(htlcWitness)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (dryrun) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    try {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      const result = await ckb.rpc.dryRunTransaction(signedTransaction)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      console.log(`Dry run success result: ${JSON.stringify(result, null, 2)}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    } catch (e) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      console.log(`Dry run failure result: ${JSON.stringify(JSON.parse(e.message), null, 2)}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  } else {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    const txHash = await ckb.rpc.sendTransaction(signedTransaction, 'passthrough')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    console.log(`Transaction hash: ${txHash}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    fs.writeFileSync('unlock_via_secret_string_result.txt', txHash)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">run()</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Finally a executable that tries to unlock HTLC guarded cell assuming the waiting period has passed:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat unlock_via_timeout.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#!/usr/bin/env node</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const { Molecule } = require('molecule-javascript')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const crc32 = require('crc32')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const CKB = require("@nervosnetwork/ckb-sdk-core").default</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const utils = require("@nervosnetwork/ckb-sdk-utils")</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const process = require('process')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const fs = require('fs')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function blake2b(buffer) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return utils.blake2b(32, null, null, utils.PERSONAL).update(buffer).digest('binary')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">if (process.argv.length !== 8) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  console.log(`Usage: ${process.argv[1]} &lt;deployed tx hash&gt; &lt;htlc cell tx hash&gt; &lt;private key&gt; &lt;node URL&gt; &lt;header hash&gt; &lt;dry run&gt;`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  process.exit(1)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const deployedTxHash = process.argv[2]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const htlcCellTxHash = process.argv[3]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const privateKey = process.argv[4]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const nodeUrl = process.argv[5]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const headerHash = process.argv[6]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const dryrun = process.argv[7] === 'true'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const run = async () =&gt; {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const ckb = new CKB(nodeUrl)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const secp256k1Dep = await ckb.loadSecp256k1Dep()</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const htlcCellTx = await ckb.rpc.getTransaction(htlcCellTxHash)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const htlcCellHeaderHash = htlcCellTx.txStatus.blockHash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const publicKey = ckb.utils.privateKeyToPublicKey(privateKey)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const publicKeyHash = `0x${ckb.utils.blake160(publicKey, 'hex')}`</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const lockScript = {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    hashType: secp256k1Dep.hashType,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    codeHash: secp256k1Dep.codeHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    args: publicKeyHash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const lockHash = ckb.utils.scriptToHash(lockScript)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const unspentCells = await ckb.loadCells({</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    lockHash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  })</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const totalCapacity = unspentCells.reduce((sum, cell) =&gt; sum + BigInt(cell.capacity), 0n)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  // For simplicity, we will just use 1 CKB as fee. On a real setup you</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  // might not want to do this.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const fee = 100000000n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const htlcCellCapacity = 200000000000n</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const customSchema = JSON.parse(fs.readFileSync('../htlc-template/src/htlc-combined.json'))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const htlcWitnessType = new Molecule(</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    customSchema.declarations.find(d =&gt; d.name == "HtlcWitness"))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const htlcWitness = htlcWitnessType.serialize([</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ['s', []],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ['i', ['0x1', '0x0', '0x0', '0x0']]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const transaction = {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    version: '0x0',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    cellDeps: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      // Due to the requirement of load0 duktape binary, JavaScript source cell</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      // should be the first one in cell deps</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        outPoint: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          txHash: deployedTxHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          index: "0x1"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        depType: 'code'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        outPoint: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          txHash: deployedTxHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          index: "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        depType: 'code'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        outPoint: secp256k1Dep.outPoint,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        depType: 'depGroup'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    headerDeps: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      htlcCellHeaderHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      headerHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    inputs: unspentCells.map(cell =&gt; ({</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      previousOutput: cell.outPoint,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      since: '0x0'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    })),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    outputs: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        lock: lockScript,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        type: null,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        capacity: '0x' + (totalCapacity + htlcCellCapacity - fee).toString(16)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    witnesses: unspentCells.map(_cell =&gt; '0x'),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    outputsData: [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      '0x',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      '0x'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  transaction.inputs.push({</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    previousOutput: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      txHash: htlcCellTxHash,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      index: "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    since: '0x0'</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  })</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  transaction.witnesses[0] = {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    lock: '',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    inputType: '',</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    outputType: ''</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  const signedTransaction = ckb.signTransaction(privateKey)(transaction)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  signedTransaction.witnesses.push(htlcWitness)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (dryrun) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    try {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      const result = await ckb.rpc.dryRunTransaction(signedTransaction)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      console.log(`Dry run success result: ${JSON.stringify(result, null, 2)}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    } catch (e) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      console.log(`Dry run failure result: ${JSON.stringify(JSON.parse(e.message), null, 2)}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  } else {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    const txHash = await ckb.rpc.sendTransaction(signedTransaction, 'passthrough')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    console.log(`Transaction hash: ${txHash}`)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    fs.writeFileSync('unlock_via_timeout_result.txt', txHash)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">run()</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We are putting the header dep for HTLC input cell at index 0, the header to test for current timestamp at index 1, hence when we are preparing witness data, we use 0x01000000 for i, which is the little endian representation for 1.</p>
<p>This also provides a different inspiration. To prove certain time has past in CKB, you can use <code>since</code> field as shown in Nervos DAO validator script, you can also include a header on chain, and rely on the header's block number or timestamp to prove that certain time has already been reached. It really depends on your use case to tell which one is the better choice here.</p>
<p>With all 4 executables ready here, we are ready to play with our HTLC script a bit. But first, let's start a new CKB dev chain.</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ export CKB="&lt;path to your ckb binary&gt;"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ $CKB --version</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">ckb 0.28.0 (728eff2 2020-02-04)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Block assembler args configured here correspond to the following private key:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># 0x0a14c6fd7af6a3f13c9e2aacad80d78968de5d068a342828080650084bf20104</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ $CKB init -c dev -C ckb-data --ba-arg 0x5a7487f529b8b8fd4d4a57c12dc0c70f7958a196</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ $CKB run -C ckb-data</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>On a different terminal, let's start a miner instance:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ $CKB miner -C ckb-data</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We are using CKB's dev chain, since there are already 2 handy <a href="https://github.com/nervosnetwork/ckb/blob/dad394ea3f50f518a40e5a8a457dfb6811ba245a/resource/specs/dev.toml#L70-L82" target="_blank" rel="noopener noreferrer">addresses</a> with issued balance, so we don't have to mine the CKB before testing. In addition, with a dev chain you can customize block issuing speed. However if you like you can also use the testnet, just remember never to use mainnet for testing here.</p>
<p>With the CKB instance running, HTLC script can be deployed and tested for real on chain.</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Make sure the HTLC script is successfully built first</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm run build</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Ensure all scripts are runnable</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP/htlc-runner</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ chmod +x deploy_scripts.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ chmod +x create_htlc_cell.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ chmod +x unlock_via_secret_string.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ chmod +x unlock_via_timeout.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Let's first deploy duktape binary and JS scripts</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./deploy_scripts.js \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ../ckb-duktape/build/load0 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ../htlc-template/build/duktape.js \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xd00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "http://127.0.0.1:8114/"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">This method is only for demo, don't use it in production</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transaction hash: 0xf30e1e8989fc3a4cb1e52dacc85090f8ff74b05e008d636b8c9154f5c296e1f4</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Let's create a HTLC cell</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./create_htlc_cell.js \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ../ckb-duktape/build/load0 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xf30e1e8989fc3a4cb1e52dacc85090f8ff74b05e008d636b8c9154f5c296e1f4 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xd00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "http://127.0.0.1:8114/" \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xc219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">This method is only for demo, don't use it in production</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transaction hash: 0x7de8ea6b0d6cb9941e76976d1d55edf844c4fa81485e00fb8eba2d161b5830cd</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># To save us the hassle of recreating cells, both unlock executables support</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># a dry run mode, where we only does full transaction verification, but do not</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># commit the success ones on chain.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># First let's show that we can unlock a HTLC cell given the right secret string</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># and lock script</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./unlock_via_secret_string.js \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xf30e1e8989fc3a4cb1e52dacc85090f8ff74b05e008d636b8c9154f5c296e1f4 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x7de8ea6b0d6cb9941e76976d1d55edf844c4fa81485e00fb8eba2d161b5830cd \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xd00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "http://127.0.0.1:8114/" \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "i am a secret" \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    true</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">This method is only for demo, don't use it in production</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Dry run success result: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "cycles": "0xb1acc38"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Given an invalid secret string, the transaction would fail the validation.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># If you have enabled debug output in CKB's configuration like mentioned here:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># https://docs-old.nervos.org/docs/essays/debug/#debug-syscall</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># you can notice the failure lines in CKB's debug logs.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./unlock_via_secret_string.js \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xf30e1e8989fc3a4cb1e52dacc85090f8ff74b05e008d636b8c9154f5c296e1f4 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x7de8ea6b0d6cb9941e76976d1d55edf844c4fa81485e00fb8eba2d161b5830cd \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xd00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "http://127.0.0.1:8114/" \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "invalid secret" \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    true</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Dry run failure result: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "code": -3,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "message": "Error { kind: ValidationFailure(-2) ...}"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Given the correct secret string but an invalid public key, this would still</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># fail the validation:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./unlock_via_secret_string.js \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xf30e1e8989fc3a4cb1e52dacc85090f8ff74b05e008d636b8c9154f5c296e1f4 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x7de8ea6b0d6cb9941e76976d1d55edf844c4fa81485e00fb8eba2d161b5830cd \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "http://127.0.0.1:8114/" \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "i am a secret" \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    true</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Dry run failure result: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "code": -3,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "message": "Error { kind: ValidationFailure(-2) ...}"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Now we've tested unlocking by providing secret string, let's try unlocking</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># via waiting enough time. In my setup, I have the following values:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># HTLC cell is packed in transaction:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># 0xf30e1e8989fc3a4cb1e52dacc85090f8ff74b05e008d636b8c9154f5c296e1f4</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># which is commited in block:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># 0x04539cff3e1a106773bc1ec35804340c0981804093ce8d7a17e9ebc37a3268ff</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># whose block number is 399.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># I'm gonna test it with block:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># 0xe93ebb311d156847fbcdc159d1fa3c38f12613121e51582272d909379c4d1a60</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># whose block number is 409, and block:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># 0x665ccfab2d854afa035f4697a2301f2bad9d4aa86506090b104f8ed18772ca01</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># whose block number is 510.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Let's first try block 510 to verify that we can unlock the HTLC cell this way:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./unlock_via_timeout.js \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xf30e1e8989fc3a4cb1e52dacc85090f8ff74b05e008d636b8c9154f5c296e1f4 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x7de8ea6b0d6cb9941e76976d1d55edf844c4fa81485e00fb8eba2d161b5830cd \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "http://127.0.0.1:8114/" \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x665ccfab2d854afa035f4697a2301f2bad9d4aa86506090b104f8ed18772ca01 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    true</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">This method is only for demo, don't use it in production</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Dry run success result: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "cycles": "0x16c500ba"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Notice here we are unlocking using lock script hash:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># 0x63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># which is different from unlocking by providing secret string.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Now let's try block 409 here:</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./unlock_via_timeout.js \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xf30e1e8989fc3a4cb1e52dacc85090f8ff74b05e008d636b8c9154f5c296e1f4 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x7de8ea6b0d6cb9941e76976d1d55edf844c4fa81485e00fb8eba2d161b5830cd \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "http://127.0.0.1:8114/" \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xe93ebb311d156847fbcdc159d1fa3c38f12613121e51582272d909379c4d1a60 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    true</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Dry run failure result: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "code": -3,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "message": "Error { kind: ValidationFailure(-2) ...}"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># As expected, this fails validatin, and if we check CKB's debug log(if you</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># have enabled it), we can find log lines containing "Timeout period has not</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># reached!", proving our script works as expected.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># One final step would checking unlocking with enough waiting, but using the</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># wrong public key.</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./unlock_via_timeout.js \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xf30e1e8989fc3a4cb1e52dacc85090f8ff74b05e008d636b8c9154f5c296e1f4 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x7de8ea6b0d6cb9941e76976d1d55edf844c4fa81485e00fb8eba2d161b5830cd \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0xd00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "http://127.0.0.1:8114/" \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    0x665ccfab2d854afa035f4697a2301f2bad9d4aa86506090b104f8ed18772ca01 \</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    true</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Dry run failure result: {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "code": -3,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "message": "Error { kind: ValidationFailure(-2) ...}"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># As expected, this also fails validation.</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Notice the generated transaction hashes might different in each different run. So make sure to adjust parameters to the cells as needed.</p>
<p>This concludes our HTLC script runs as expected(well, excluding those vulnarable situations), hooray!</p>
<h1>Compute Intensive Code in JavaScript</h1>
<p>Let's jump back for a second. I've been avoiding doing signatue verification code in our HTLC script written in JavaScript here. You might notice we also use a very simple CRC32 hashing algorithm, instead of the more secure hashing algorithms such as blake2b. While one major reason I did, is for the simplicity of this post(if you read till this point you will notice this post is already insanely long!), it is still not recommended to do those operations in JavaScript since:</p>
<ul>
<li>A crypto algorithm requires precise implementation, while I'm not saying you cannot do that, it certainly requires more care to build crypto algorithms in a higher-level language like JavaScript. It's much better to leverage existing battle-tested libraries written in C or Rust.</li>
<li>Crypto algorithms are typical compute intensive code, since we are running JavaScript code in duktape, it can easily slow your code by 10x or even 100x. A native implementation can be much faster and saves significant cycles on CKB.</li>
</ul>
<p>Right now the <a href="https://github.com/xxuejie/ckb-duktape" target="_blank" rel="noopener noreferrer">duktape</a> distribution used here only contains duktape with no external libraries. In the future I might add other distributions with certain crypto algorithms shipped together, such as secp256k1 and blake2b. This way you will be able to invoke fast and secure crypto algorithms well within JavaScript. But please also remember sometimes, the delegate patterns mentioned above might suit your use case better.</p>
<h1>Recap</h1>
<p>I sincerely hope you have read till this far, instead of skipping it. This is a ridiculously long post, but it contains a lot of useful information when building scripts on CKB:</p>
<ul>
<li>How to prepare a debugging environment that aids writting the script</li>
<li>How to build custom data structure in molecule format</li>
<li>How to serialize/deserialize molecule data structures</li>
<li>How to include external libraries on npm and pack a single JavaScript for CKB use</li>
</ul>
<p>While I might still add more posts to this series if I noticed interesting stuff to write, I'm sure the existing 7 posts in this series, together with <a href="https://justjjy.com/Build-CKB-contract-with-Rust-part-1" target="_blank" rel="noopener noreferrer">many</a> <a href="https://justjjy.com/CKB-contract-in-Rust-part-2-Rewrite-contract-with-ckb" target="_blank" rel="noopener noreferrer">other</a> <a href="https://docs-old.nervos.org/docs/essays/debug/" target="_blank" rel="noopener noreferrer">awesome</a> <a href="https://mp.weixin.qq.com/s/9cP_Qik-AsdpiqL-q0ac4w" target="_blank" rel="noopener noreferrer">posts</a> by my colleagues, have well prepared you to build awesome things on CKB. We are all prepared to amazed by the beautiful things you build on CKB :)</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduction to CKB Script Programming 8: Performant WASM]]></title>
            <link>https://docs.nervos.org/blog/intro-to-ckb-script-programming-8</link>
            <guid>https://docs.nervos.org/blog/intro-to-ckb-script-programming-8</guid>
            <pubDate>Mon, 02 Mar 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[In an earlier post, I've shown you that you can have WASM programming running on CKB, with a little caveat that the WASM programs might not be so performant. I also mentioned that there is a potential solution that could solve the problem. And now it's the day! We now have a new project that could be used to generate performant WASM programs. Let's see how it works in this post.]]></description>
            <content:encoded><![CDATA[<p>In an <a href="https://docs.nervos.org/2019_10_09_introduction_to_ckb_script_programming_wasm_on_ckb/">earlier post</a>, I've shown you that you can have WASM programming running on CKB, with a little caveat that the WASM programs might not be so performant. I also mentioned that there is a potential solution that could solve the problem. And now it's the day! We now have a new <a href="https://github.com/xxuejie/wavm-aot-generator" target="_blank" rel="noopener noreferrer">project</a> that could be used to generate performant WASM programs. Let's see how it works in this post.</p>
<p>(If you are impatient, you can skip this section and jump directly to Examples)</p>
<p>In the previous post, we are translating the WebAssembly programs back to C code, then compile it from C code to RISC-V again. But this has many drawbacks:</p>
<ul>
<li>It's not always possible to preserve all the optimizations done on the code in a C intermediate layer.</li>
<li>Due to limitations in C, it is not possible to fully customize memory layout for the maximum performance.</li>
<li>A C layer can be flaky at times and is not always easy to debug.</li>
</ul>
<p>Here we are trying a different solution: <a href="https://github.com/WAVM/WAVM" target="_blank" rel="noopener noreferrer">WAVM</a> is a high performance(<a href="https://00f.net/2019/10/22/updated-webassembly-benchmark/" target="_blank" rel="noopener noreferrer">benchmarks</a> show this is the highest performance WASM implementation so far) translation layer that compiles WASM code directly to native code via LLVM. Since LLVM 9+ has official RISC-V support, we can just retarget WAVM to RISC-V code, it will then be able to translate WASM program directly to RISC-V native code.</p>
<p>There's one additional problem: WAVM requires a runtime part to complement the native with surrounding environments. Currently this is included within WAVM with dependency on LLVM, which makes the binary quite huge. One day it suddenly occurs to me that all the information needed to build the runtime, is already included in the original WASM file, so we can just build a separate project, that processes the original WASM file and emits a minimal runtime part in plain C code, then we link it together with generated native code, the result will be a single RISC-V native program that is compiled from WASM code, and can run independently.</p>
<h1>Examples</h1>
<p>Here we will use the exact same examples as the previous post: the fibonacci code written in AssemblyScript, and secp256k1 example in pure Rust. We will do a side-by-side comparison on the generated code size, and cycles consumed running in CKB VM. For the sake of completeness, we will also include native versions written in pure C in each example. As we will see below, even if our current WASM solution still has way to go towards the pure C version, it is already quite close and could enable many use cases.</p>
<p>First let's clone all the needed repos and do necessary preparations:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ export TOP=$(pwd)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/AssemblyScript/assemblyscript.git</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd assemblyscript</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git checkout b433bc425633c3df6a4a30c735c91c78526a9eb7</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm install</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone --recursive https://github.com/WebAssembly/wabt</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd wabt</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git checkout bec78eafbc203d81b9a6d1ce81f5a80dd7bf692a</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ mkdir build</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd build</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cmake ..</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cmake --build .</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/xxuejie/WAVM</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd WAVM</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git checkout cb35225feeb4ba1b5a9c73cbbdb07f4cace9b359</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ mkdir build</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd build</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># Make sure you are using LLVM 9+, you might need to tweak this path depending</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># on your environment</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cmake .. -DLLVM_DIR=/usr/lib/llvm-9/lib/cmake/llvm</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cmake --build .</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/xxuejie/wavm-aot-generator</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd wavm-aot-generator</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git checkout 8c818747eb19494fc9c5e0289810aa7ad484a22e</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cargo build --release</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/xxuejie/ckb-standalone-debugger</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ckb-standalone-debugger</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git checkout 15e8813b8cb886e95e2c81bbee9f26d47a831850</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd bins</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cargo build --release</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/xxuejie/ckb-binary-patcher</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ckb-binary-patcher</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git checkout 930f0b468a8f426ebb759d9da735ebaa1e2f98ba</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ckb-binary-patcher</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cargo build --release</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/nervosnetwork/ckb-c-stdlib</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ckb-c-stdlib</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git checkout 693c58163fe37d6abd326c537447260a846375f0</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="assemblyscript-example">AssemblyScript Example<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-8#assemblyscript-example" class="hash-link" aria-label="Direct link to AssemblyScript Example" title="Direct link to AssemblyScript Example">​</a></h2>
<p>Here's our old fibonacci example in AssemblyScript, let's compile it to WebAssembly program first:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat &lt;&lt; EOF &gt; fib.ts</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">export function fib(n: i32): i32 {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  var a = 0, b = 1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    for (let i = 0; i &lt; n; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        let t = a + b; a = b; b = t;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return b;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">EOF</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ assemblyscript/bin/asc fib.ts -b fib.wasm -O3</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We will compile the WASM code to 2 different versions: C code, and RISC-V native code.</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ wabt/build/wasm2c fib.wasm -o fib.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ WAVM/build/bin/wavm compile --target-triple riscv64 fib.wasm fib_precompiled.wasm</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ wavm-aot-generator/target/release/wavm-aot-generator fib_precompiled.wasm fib_precompiled</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You might noticed that instead of generating native RISC-V code, we are using WAVM to generated a <code>precompiled object</code> formatted file. This is essentially the original WASM file with native code embedded in a custom section, this way we can feed a single file to our generator for convenience reasons.</p>
<p>Let's attach 2 distinct wrapper files used in 2 WASM solutions, and also provide a native implementation:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat &lt;&lt; EOF &gt; fib_wabt_main.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;stdio.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;stdlib.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "ckb_syscalls.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "fib.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">void (*Z_envZ_abortZ_viiii)(u32, u32, u32, u32);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">void env_abort(u32 a, u32 b, u32 c, u32 d) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  abort();</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">int main() {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint32_t value;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint64_t len = 4;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  int ret = ckb_load_witness((void*) &amp;value, &amp;len, 0, 0,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                             CKB_SOURCE_GROUP_INPUT);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (ret != CKB_SUCCESS) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return ret;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (len &lt; 4) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return -1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  init();</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  u8 result = Z_fibZ_ii(value);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return result;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">EOF</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat &lt;&lt; EOF &gt; fib_wavm_main.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "fib_precompiled_glue.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "abi/ckb_vm_wasi_abi.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "ckb_syscalls.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">void* wavm_env_abort(void* dummy, int32_t code, int32_t a, int32_t b, int32_t c)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">{</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ckb_exit(code);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return dummy;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">int main() {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint32_t value;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint64_t len = 4;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  int ret = ckb_load_witness((void*) &amp;value, &amp;len, 0, 0,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                             CKB_SOURCE_GROUP_INPUT);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (ret != CKB_SUCCESS) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return ret;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (len &lt; 4) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return -1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  wavm_ret_int32_t wavm_ret = wavm_exported_function_fib(NULL, value);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return wavm_ret.value;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">EOF</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat &lt;&lt; EOF &gt; fib_native_main.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "ckb_syscalls.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">int32_t fib(int32_t n) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  int32_t a = 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  int32_t b = 1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (int32_t i = 0; i &lt; n; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    int32_t t = a + b;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    a = b;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    b = t;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return b;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">int main() {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint32_t value;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint64_t len = 4;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  int ret = ckb_load_witness((void*) &amp;value, &amp;len, 0, 0,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                             CKB_SOURCE_GROUP_INPUT);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (ret != CKB_SUCCESS) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return ret;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (len &lt; 4) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return -1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return fib(value);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">EOF</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You might noticed that we altered the wabt wrapper used in previous post, so that all 3 versions here load the input to fibonacci function from witness data, this way we can set the same standard for comparison.</p>
<p>Let's compile the 3 files first:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ sudo docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191209 bash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@7f24745ca702:/# cd /code</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@7f24745ca702:/code# riscv64-unknown-elf-gcc -O3 -I ckb-c-stdlib -I wavm-aot-generator -I wabt/wasm2c fib_wabt_main.c fib.c wabt/wasm2c/wasm-rt-impl.c -o fib_wabt</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@7f24745ca702:/code# riscv64-unknown-elf-gcc -O3 -I ckb-c-stdlib -I wavm-aot-generator -I wabt/wasm2c fib_wavm_main.c wavm-aot-generator/abi/riscv64_runtime.S fib_precompiled.o -o fib_wavm -Wl,-T wavm-aot-generator/abi/riscv64.lds</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@7f24745ca702:/code# riscv64-unknown-elf-gcc -O3 -I ckb-c-stdlib -I wavm-aot-generator -I wabt/wasm2c fib_native_main.c -o fib_native</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@7f24745ca702:/code# exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ckb-binary-patcher/target/release/ckb-binary-patcher -i fib_wavm -o fib_wavm_patched</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Due to a <a href="https://github.com/nervosnetwork/ckb-vm/issues/92" target="_blank" rel="noopener noreferrer">VM bug</a>, a <a href="https://github.com/xxuejie/ckb-binary-patcher" target="_blank" rel="noopener noreferrer">patcher</a> utility has been provided to workaround RISC-V code that would generate the bug. Even though we only observed LLVM affected by this bug(GCC has optimizations that would generate different code), it still recommended to run the patcher against any script that you would want to run on CKB.</p>
<p>We also prepare a runner to run the scripts:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat &lt;&lt; EOF &gt; runner.rb</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#!/usr/bin/env ruby</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">require "rbnacl"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">def bin_to_hex(bin)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "0x#{bin.unpack1('H*')}"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">end</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">def blake2b(data)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  RbNaCl::Hash::Blake2b.digest(data,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                               personal: "ckb-default-hash",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                               digest_size: 32)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">end</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">if ARGV.length != 2</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  STDERR.puts "Usage: runner.rb &lt;script file&gt; &lt;witness args&gt;"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  exit 1</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">end</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">script_binary = File.read(ARGV[0])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">script_hash = blake2b(script_binary)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">tx = DATA.read.sub("@FIB_CODE", bin_to_hex(script_binary))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">       .sub("@FIB_HASH", bin_to_hex(script_hash))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">       .sub("@FIB_ARG", ARGV[1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">File.write("tx.json", tx)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">commandline = "ckb-standalone-debugger/bins/target/release/ckb-debugger --tx-file tx.json --script-group-type type -i 0 -e input"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">STDERR.puts "Executing: #{commandline}"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">exec(commandline)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">__END__</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">{</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "mock_info": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "inputs": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "input": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "previous_output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "tx_hash": "0xa98c57135830e1b91345948df6c4b8870828199a786b26f09f7dec4bc27a73da",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "since": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "capacity": "0x4b9f96b00",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "lock": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "args": "0x",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "type": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "args": "0x",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "code_hash": "@FIB_HASH",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "data": "0x"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "cell_deps": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "cell_dep": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "out_point": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "tx_hash": "0xfcd1b3ddcca92b1e49783769e9bf606112b3f8cf36b96cac05bf44edcf5377e6",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "dep_type": "code"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "capacity": "0x702198d000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "lock": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "args": "0x",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "type": null</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "data": "@FIB_CODE"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "header_deps": []</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "tx": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "version": "0x0",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "cell_deps": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "out_point": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "tx_hash": "0xfcd1b3ddcca92b1e49783769e9bf606112b3f8cf36b96cac05bf44edcf5377e6",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "dep_type": "code"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "header_deps": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "inputs": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "previous_output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "tx_hash": "0xa98c57135830e1b91345948df6c4b8870828199a786b26f09f7dec4bc27a73da",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "since": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "outputs": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "capacity": "0x0",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "lock": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "args": "0x",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "type": null</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "witnesses": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      "@FIB_ARG"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "outputs_data": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      "0x"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">EOF</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ chmod +x runner.rb</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now we can take a look at the binary size of each version, and run the 3 versions of fibonacci calculation:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ls -lh fib_wabt fib_wavm_patched fib_native</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">-rwxr-xr-x 1 root 11K Mar  3 03:27 fib_native*</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">-rwxr-xr-x 1 root 53K Mar  3 03:26 fib_wabt*</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">-rwxr-xr-x 1 root 88K Mar  3 03:26 fib_wavm_patched*</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb fib_wabt 0x10000000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(61)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 549478</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 6530, running cycles: 542948</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb fib_wabt 0x20000000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(-30)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 549590</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 6530, running cycles: 543060</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb fib_wabt 0x00010000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(29)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 551158</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 6530, running cycles: 544628</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb fib_wavm_patched 0x10000000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(61)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 22402</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 19696, running cycles: 2706</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb fib_wavm_patched 0x20000000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(-30)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 22578</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 19696, running cycles: 2882</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb fib_wavm_patched 0x00010000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(29)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 25042</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 19696, running cycles: 5346</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb fib_native 0x10000000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(61)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 3114</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 1137, running cycles: 1977</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb fib_native 0x20000000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(-30)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 3226</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 1137, running cycles: 2089</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb fib_native 0x00010000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(29)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 4794</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 1137, running cycles: 3657</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The input value is encoded in witness part as 32-bit unsigned little endian integer, meaning <code>0x10000000</code>, <code>0x20000000</code> and <code>0x00010000</code> here represent <code>16</code>, <code>32</code> and <code>256</code> respectively.</p>
<p>Since CKB VM emits 8-bit signed value as output, the calculated value are truncated here. But we do not care so much about the actual fibonacci number(well of course, assuming the 3 versions generate the same result), it's the cycle consumption that we care about here.</p>
<p>Some insights can thus be deduced from the values:</p>
<ul>
<li>The WAVM version generates the biggest binary size(88K), in fact it also requires loading more bytes into the VM as confirmed by <code>transfer cycles</code> of 19696(roughly speaking, 1 transfer cycle means 4 bytes loaded into the VM).</li>
<li>The WABT version and native version both take about 7 cycles to calculate one round of fibonacci iteration, while the WAVM version takes about 11 cycles to calculate one round of iteration</li>
<li>However, the WAVM version requires only about 2530 cycles to set up the running environment, while the WABT version takes about 542836 cycles to set up.</li>
</ul>
<p>We can see that the WAVM version does take significant less cycles in the initial setup(this is hugely due to the custom memory layout we can leverage in WAVM version), but the WAVM version is slightly slower per fibonacci iteration. This might be due to the fact that LLVM still needs some work to catch up GCC's code generation quality for RISC-V, and it could also be that fibonacci is so simple, that GCC can perfectly pick up the calculation structure from the restored C code. For more complex examples, this might not be the case anymore.</p>
<p>I personally did do some investigation into the large binary size of WAVM binary, and the problem, is that all the symbols generated in WAVM, are declared public symbols. That means we cannot rely on dead code elimination(DCE) to purge those variables and functions that we are not used, hence a larger binary is generated here. If the original WASM program is generated by Rust or LLVM directly, this won't be a problem since DCE is already performed, but Assemblyscript tends to do less DCE, hence we have a larger binary. Later I might look into WAVM to see if there's a way we can tweak non-exported functions to be module local, if that can be resolved, we should be able to reduce the binary size of WAVM version to the same level like the other solutions.</p>
<h1>Rust Secp256k1 Example</h1>
<p>Let's also try the more complicated Rust based secp256k1 example:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/nervosnetwork/wasm-secp256k1-test</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd wasm-secp256k1-test</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cargo build --release --target=wasm32-unknown-unknown</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ wabt/bin/wasm2c wasm-secp256k1-test/target/wasm32-unknown-unknown/release/wasm-secp256k1-test.wasm -o secp.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># There's a symbol confliction in the latest versioni of gcc with wabt here, this</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"># can serve as a temporary solutin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ sed -i s/bcmp/bcmp1/g secp.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ WAVM/build/bin/wavm compile --target-triple riscv64 wasm-secp256k1-test/target/wasm32-unknown-unknown/release/wasm-secp256k1-test.wasm secp_precompiled.wasm</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ wavm-aot-generator/target/release/wavm-aot-generator secp_precompiled.wasm secp_precompiled</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat &lt;&lt; EOF &gt; secp_wabt_main.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;stdio.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;stdlib.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "ckb_syscalls.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "secp.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">int main() {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint32_t value;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint64_t len = 4;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  int ret = ckb_load_witness((void*) &amp;value, &amp;len, 0, 0,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                             CKB_SOURCE_GROUP_INPUT);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (ret != CKB_SUCCESS) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return ret;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (len &lt; 4) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return -1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  init();</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint32_t times = value &gt;&gt; 8;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  value = value &amp; 0xFF;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint8_t result = 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (int i = 0; i &lt; times; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    result += Z_runZ_ii(value);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return result;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">EOF</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat &lt;&lt; EOF &gt; secp_wavm_main.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "secp_precompiled_glue.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "abi/ckb_vm_wasi_abi.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "ckb_syscalls.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">int main() {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint32_t value;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint64_t len = 4;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  int ret = ckb_load_witness((void*) &amp;value, &amp;len, 0, 0,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                             CKB_SOURCE_GROUP_INPUT);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (ret != CKB_SUCCESS) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return ret;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (len &lt; 4) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return -1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint32_t times = value &gt;&gt; 8;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  value = value &amp; 0xFF;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint8_t result = 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (int i = 0; i &lt; times; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ckb_debug("One run!");</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    wavm_ret_int32_t wavm_ret = wavm_exported_function_run(NULL, value);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    result += wavm_ret.value;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return result;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">EOF</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now we can compile the code, then compare binary size as well as running cycles:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ sudo docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191209 bash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@a237c0d00b1c:/# cd /code/</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@a237c0d00b1c:/code# riscv64-unknown-elf-gcc -O3 -I ckb-c-stdlib -I wavm-aot-generator -I wabt/wasm2c secp_wabt_main.c secp.c wabt/wasm2c/wasm-rt-impl.c -o secp_wabt</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@a237c0d00b1c:/code# riscv64-unknown-elf-gcc -O3 -I ckb-c-stdlib -I wavm-aot-generator -I wabt/wasm2c secp_wavm_main.c wavm-aot-generator/abi/riscv64_runtime.S secp_precompiled.o -o secp_wavm -Wl,-T wavm-aot-generator/abi/riscv64.lds</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@a237c0d00b1c:/code# exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ckb-binary-patcher/target/release/ckb-binary-patcher -i secp_wavm -o secp_wavm_patched</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ls -l secp_wabt secp_wavm_patched</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">-rwxrwxr-x 1 ubuntu 1791744 Mar  3 05:27 secp_wabt*</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">-rw-rw-r-- 1 ubuntu 1800440 Mar  3 05:29 secp_wavm_patched</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb secp_wabt 0x01010000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 35702943</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 438060, running cycles: 35264883</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb secp_wabt 0x01050000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 90164183</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 438060, running cycles: 89726123</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb secp_wavm_patched 0x01010000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 10206568</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 428764, running cycles: 9777804</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb secp_wavm_patched 0x01050000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 49307936</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 428764, running cycles: 48879172</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Like the previous case, we can deduce facts from the values as well:</p>
<ul>
<li>The binary sizes generated by the 2 version are only slightly different, WAVM has a slightly larger binary but the bytes needed to load into VM is less.</li>
<li>In this case, a single secp256k1 verification step takes 9775342 in the WAVM version, while 13615310 cycles are needed in the WABT version. Here we can see doing translations in LLVM directly does provide better performance than a restored C version in WABT.</li>
<li>For such a complex program, the WAVM version still only takes 2462 cycles to set up, while the WABT version would take an enourmous 21649573 cycles to set up things. Here WAVM version can provide you with big wins.</li>
</ul>
<p>Since the current direct path from Rust to RISC-V does not allow std to be used. We cannot provide a similar native version directly. But just for the curious ones, I still provide a similar function in pure C, and we can measure the cycles taken by the C version compiled directly into RISC-V:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone --recursive https://github.com/nervosnetwork/ckb-vm-bench-scripts</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ckb-vm-bench-scripts</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git checkout f7ab37c055b1a59bbc4f931c732331642c728c1d</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ sudo docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191209 bash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@ad22c452cb54:/# cd /code/ckb-vm-bench-scripts</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@ad22c452cb54:/code/ckb-vm-bench-scripts# make</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">(omitted ...)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@ad22c452cb54:/code/ckb-vm-bench-scripts# exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb ckb-vm-bench-scripts/build/secp256k1_bench 0x01010000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 1621594</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 272630, running cycles: 1348964</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ./runner.rb ckb-vm-bench-scripts/build/secp256k1_bench 0x01050000</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 7007598</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 272630, running cycles: 6734968</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>As we can see here, the C native version takes 1346501 cycles per secp256k1 step, and 2463 cycles for initial bookkeeping work. Both the binary sizes and loaded bytes are also smaller.</p>
<p>I do want to mention here that we are not comparing the same code here, the C version and Rust version use different implementation, and we haven't benched the quality of the 2 implementations directly. That being said, assuming the 2 versions have similar performance, the Rust code, compiled to WASM first, then to RISC-V, is roughly 7x the performance of C code. Considering bound checking logic might also be performed by the Rust version, I would consider this is good performance for many many use cases. There're a whole lot of scripts that can work with this level of performance. What's more, you can always combine the C implemented performance oriented code and Rust implemented logic code together to enjoy the best of both works. And we haven't mentioned the best of this new route. Last but not least, all the involved projects, including Rust, LLVM, WAVM and our generator are active projects with development work going on, soon this gap might become much narrower with progresses made by all the awesome engineers.</p>
<h1>WASI</h1>
<p>I kept talking about doing Rust on CKB via WASM, my colleague has <a href="https://justjjy.com/Build-CKB-contract-with-Rust-part-1" target="_blank" rel="noopener noreferrer">proved</a> there is a path you can go directly from Rust to RISC-V, what does a WASM intermediate path help here? The problem with a native path, is that Rust's std is not supported in RISC-V port, to make matters worse, libc binding is also absent. This means you will really have to work with core Rust, a minimal and limited set of Rust. Please don't get me wrong, there's nothing bad about going with core Rust, if your use case is enough with Rust's std, you are perfectly good going that path. But I do want to provide a different path, where std is available, so most Rust libraries on crates can be used to build awesome CKB scripts. This is what the WASM path can enable us with WASI.</p>
<p>If you haven't heard of it, <a href="https://wasi.dev/" target="_blank" rel="noopener noreferrer">WASI</a> is a standard way of interfacing with the running environment for a WebAssembly program. It has <a href="https://github.com/alexcrichton/cc-rs/issues/447" target="_blank" rel="noopener noreferrer">been</a> <a href="https://github.com/alexcrichton/cc-rs/issues/446" target="_blank" rel="noopener noreferrer">proved</a> that Rust's WASM future lies in a new <code>wasm32-wasi</code> target. By doing the WASM intermediate step, we can build WASI support right into CKB script, enjoying the future-proof <code>wasm32-wasi</code> target of Rust! In fact, WAVM already provides an <a href="https://github.com/xxuejie/WAVM/blob/master/Examples/helloworld.wast" target="_blank" rel="noopener noreferrer">example</a> that leverages 2 of WASI's API, let's see if we can get that to work on CKB:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ WAVM/build/bin/wavm compile --target-triple riscv64 WAVM/Examples/helloworld.wast helloworld_precompiled.wasm</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ wavm-aot-generator/target/release/wavm-aot-generator helloworld_precompiled.wasm helloworld_precompiled</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat &lt;&lt; EOF &gt; helloworld_wavm_main.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "helloworld_precompiled_glue.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "abi/ckb_vm_wasi_abi.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">/* main is already generated via wavm-aot-generator */</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">EOF</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ sudo docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191209 bash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@d28602dba318:/# cd /code</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@d28602dba318:/code# riscv64-unknown-elf-gcc -O3 -I ckb-c-stdlib -I wavm-aot-generator -I wabt/wasm2c helloworld_wavm_main.c wavm-aot-generator/abi/riscv64_runtime.S</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">helloworld_precompiled.o -o helloworld_wavm -Wl,-T wavm-aot-generator/abi/riscv64.lds</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@d28602dba318:/code# exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ckb-binary-patcher/target/release/ckb-binary-patcher -i helloworld_wavm -o helloworld_wavm_patched</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug ./runner.rb helloworld_wavm_patched 0x</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x86cfac3b49b8f97f913aa5a09d02ad1e5b1ab5be0be793815e9cb714ba831948) DEBUG OUTPUT: Hello World!</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 20260</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 17728, running cycles: 2532</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We can see the WASI APIs work perfectly! This is because I have already provided the <a href="https://github.com/xxuejie/wavm-aot-generator/blob/8c818747eb19494fc9c5e0289810aa7ad484a22e/abi/ckb_vm_wasi_abi.h#L51-L91" target="_blank" rel="noopener noreferrer">implementation</a> for the 2 APIs used here. While it is incomplete now, I will work to add shims for all WASI APIs. After that we can have Rust programs, with std supported, compiled to <code>wasm32-wasi</code> target's WASM code, then translated to RISC-V perfectly.</p>
<p>You see many different blockchains claiming they use WebAssembly everyday, but what they don't tell you, is that WebAssembly is designed to have many flavors, and they just choose to support one of them. In fact <a href="https://github.com/paritytech/substrate/issues/4043" target="_blank" rel="noopener noreferrer">many</a> <a href="https://github.com/confio/cosmwasm/blob/master/Building.md#requirements" target="_blank" rel="noopener noreferrer">famous</a> <a href="https://github.com/CasperLabs/CasperLabs/tree/dev/execution-engine/cargo-casperlabs#building-the-contract~" target="_blank" rel="noopener noreferrer">blockchains</a> <a href="https://github.com/EOSIO/eosio.cdt/blob/master/tools/external/wabt/src/emscripten-helpers.cc" target="_blank" rel="noopener noreferrer">only</a> tend to support a bare minimal WebAssembly program. While most of them let you use Rust, they only use the flaky and could-be-deprecated <code>wasm32-unknown-unknown</code> target. As a result, they either just disable Rust std directly, claiming you don't need it, or has flaky support that might break going into the future, or they cannot afford to change the code for compatibility reasons. On the other hand, you can enjoy WASI and full feature Rust in CKB. Many ask us why we don't use WebAssembly directly, I would say that we are the first one, or at least among the first ones to get WebAssembly right on blockchains.</p>
<h1>"Vice Verca" doesn't always work well</h1>
<p>One recurring topic we heard, is that if you can translate WASM to RISC-V, you can also translate RISC-V to WASM! In a sense that is true, but there's a difference betweeen one thing that works, and one thing that works well.</p>
<p>RISC-V, due to its design, is a very simple specification that maps extremely well to modern day CPUs. If you check our VM implementation, you might notice that most RISC-V instructions map directly onto a dozen x86-64 CPU instructions. We are just building a minimal secure layer that works on top of the CPUs in your machines. WASM, on the other hand, is a <a href="https://webassembly.org/docs/future-features/" target="_blank" rel="noopener noreferrer">beast</a> much like JVM, there are tons of features in the spec already, there are also tons of features being added to the spec everyday. Many of the new features don't have direct mappings on CPUs, ranging from lower level instructions such as <code>memory.grow</code> or <code>callIndirect</code>, to higher level features such as garbage collections, or threading. When you pick WebAssembly as your blockchain's engine, you will have to pick a set of features, and decide how/if you want to migrate when new features keep coming out. To complicate this matter, you cannot just change the implementation of some features in your current WebAssembly engine, cuz that might bring incompatible changes.</p>
<p>When you pick RISC-V as the underlying engine, you don't have such concerns. RISC-V is designed for hardware that never changes. When the spec is fixed, it will be fixed forever, and all compilers have to respect bugs in the spec. And when you are implementing WebAssembly programs on top of RISC-V, you are free to change the implementations of higher constructs in WebAssembly anyway you want. For example, you might discover a new garbage collection algorithm that will help your smart contracts, you can deploy the algorithm by upgrading the a different smart contract, no forks are needed to support this. All of these are extremely hard to being even impossible if you tackle the problem starting from a WebAssembly engine. That is where I believe the true beauty of CKB's unique design lies.</p>
<h1>Recap</h1>
<p>Here's one suggestion: if someone tells you his/her blockchain uses WebAssembly, do yourself a favor, and ask what specific spec his/her WebAssembly engine uses, and how he/she plan to tackle the problem when more features are added to the WebAssembly specification. WebAssembly is an evergrowing specification due to its Web roots, picking one specification and freeze there is never a good strategy for employing WebAssembly in a stack. There's nothing wrong relying on WebAssembly in the blockchain world, but it matters if WebAssembly is used in the correct way. To me, CKB is one example that WebAssembly is used in the correct way with future issues considered. I do believe you will thank yourself years later, if you take the extra effort ensuring your choice of blockchain deploys WebAssembly the correct way.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduction to CKB Script Programming 9: Cycle Reductions in Duktape Script]]></title>
            <link>https://docs.nervos.org/blog/intro-to-ckb-script-programming-9</link>
            <guid>https://docs.nervos.org/blog/intro-to-ckb-script-programming-9</guid>
            <pubDate>Thu, 19 Mar 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[As shown earlier, plain JavaScript can be used to build CKB scripts. But if you have tried this route before, one problem you would notice, is that JavaScript based scripts tend to consume much more cycles than a native version. While this is less of an issue in experimenting, it is very real in production environment]]></description>
            <content:encoded><![CDATA[<p>As shown earlier, plain JavaScript can be used to build CKB scripts. But if you have tried this route before, one problem you would notice, is that JavaScript based scripts tend to consume much more cycles than a native version. While this is less of an issue in experimenting, it is very real in production environment: more cycles can naturally be reflected in more transaction fees. It's obvious that the following solutions can be used to tackle this problem:</p>
<ol>
<li>Rewrite a JavaScript in a native compiled language, such as C or Rust;</li>
<li>Use better algorithms that require less cycles;</li>
</ol>
<p>In this post, we would take a different path, and take a look at JavaScript scripts alone. Even though JavaScript can consume more cycles, it still allows fast iteraction, which might be critical in certain use cases. So the question I want to ask here is: if we decide to use JavaScript to build our CKB scripts, and we have already improved the algorithms and implementations to an optimal state, are there any other steps we can take to further optimize cycle reductions? Here we shall see some attempts at the problem.</p>
<p>We will build a simple script here that reads and prints current script args. To build the JavaScript script, we will first need the <a href="https://github.com/xxuejie/ckb-duktape-template" target="_blank" rel="noopener noreferrer">duktape template</a>:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ export TOP=$(pwd)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/xxuejie/ckb-duktape-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ckb-duktape-template</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git checkout 1a3536ae1dc14abe1e91461ab356e8967cde8d7b</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm i</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat &lt;&lt; EOF &gt; src/index.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">import { Script } from "../schema/blockchain.js"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">function bytesToHex(b) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return "0x" + Array.prototype.map.call(</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    new Uint8Array(b),</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    function(x) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      return ('00' + x.toString(16)).slice(-2)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ).join('')</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const script = new Script(CKB.load_script(0))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">const args = script.getArgs().raw()</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">CKB.debug(bytesToHex(args))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">EOF</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ npm run build</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Note this example also levearges the rebuilt <a href="https://github.com/xxuejie/moleculec-es" target="_blank" rel="noopener noreferrer">Molecule JavaScript plugin</a>. Compared to the previous one, it provides a better API, while at the same time saving huge code size and runtime cycles.</p>
<p>Let's get a baseline number first:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone --recursive https://github.com/xxuejie/ckb-duktape</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ckb-duktape</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git checkout d6241938247b402ec56c7af218acfc9049ac753d</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191209 bash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@0d31cad7a539:~# cd /code</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@0d31cad7a539:/code# make</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@0d31cad7a539:/code# exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git clone https://github.com/xxuejie/ckb-standalone-debugger</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd ckb-standalone-debugger/bins</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ git checkout 3c503b95962e29057b248aeed4f639180c132fff</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cargo build --release</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat &lt;&lt; EOF &gt; runner.rb</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#!/usr/bin/env ruby</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">require "rbnacl"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">def bin_to_hex(bin)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "0x#{bin.unpack1('H*')}"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">end</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">def blake2b(data)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  RbNaCl::Hash::Blake2b.digest(data,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                               personal: "ckb-default-hash",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                               digest_size: 32)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">end</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">if ARGV.length != 2 &amp;&amp; ARGV.length != 3</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  STDERR.puts "Usage: runner.rb &lt;duktape file&gt; &lt;script file&gt; &lt;optional dump file&gt;"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  exit 1</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">end</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duktape_binary = File.read(ARGV[0])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">duktape_hash = blake2b(duktape_binary)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">script_binary = File.read(ARGV[1])</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">tx = DATA.read.sub("@DUKTAPE_CODE", bin_to_hex(duktape_binary))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">       .sub("@DUKTAPE_HASH", bin_to_hex(duktape_hash))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">       .sub("@SCRIPT_CODE", bin_to_hex(script_binary))</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">File.write("tx.json", tx)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">commandline = "ckb-standalone-debugger/bins/target/release/ckb-debugger --tx-file tx.json --script-group-type lock -i 0 -e input"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">if ARGV.length == 3</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  commandline += " -d #{ARGV[2]}"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">end</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">STDERR.puts "Executing: #{commandline}"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">exec(commandline)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">__END__</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">{</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "mock_info": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "inputs": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "input": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "previous_output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "tx_hash": "0xa98c57135830e1b91345948df6c4b8870828199a786b26f09f7dec4bc27a73da",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "since": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "capacity": "0x4b9f96b00",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "lock": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "args": "0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947c219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd970dd9a8",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "code_hash": "@DUKTAPE_HASH",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "type": null</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "data": "0x"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "cell_deps": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "cell_dep": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "out_point": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "tx_hash": "0xfcd1b3ddcca92b1e49783769e9bf606112b3f8cf36b96cac05bf44edcf5377e6",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "dep_type": "code"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "capacity": "0x702198d000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "lock": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "args": "0x",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "type": null</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "data": "@SCRIPT_CODE"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "cell_dep": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "out_point": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "tx_hash": "0xfcd1b3ddcca92b1e49783769e9bf606112b3f8cf36b96cac05bf44edcf5377e6",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "index": "0x1"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "dep_type": "code"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "capacity": "0x702198d000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "lock": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "args": "0x",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">            "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "type": null</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "data": "@DUKTAPE_CODE"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "header_deps": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "compact_target": "0x1a1e4c2f",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "hash": "0x51d199c4060f703344eab3c9b8794e6c60195ae9093986c35dba7c3486224409",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "number": "0xd8fc4",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "parent_hash": "0xc02e01eb57b205c6618c9870667ed90e13adb7e9a7ae00e7a780067a6bfa6a7b",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "nonce": "0xca8c7caa8100003400231b4f9d6e0300",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "timestamp": "0x17061eab69e",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "transactions_root": "0xffb0863f4ae1f3026ba99b2458de2fa69881f7508599e2ff1ee51a54c88b5f88",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "proposals_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "uncles_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "version": "0x0",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "epoch": "0x53f00fa000232",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "dao": "0x4bfe53a5a9bb9a30c88898b9dfe22300a58f2bafed47680000d3b9f5b6630107"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  "tx": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "version": "0x0",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "cell_deps": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "out_point": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "tx_hash": "0xfcd1b3ddcca92b1e49783769e9bf606112b3f8cf36b96cac05bf44edcf5377e6",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "dep_type": "code"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "out_point": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "tx_hash": "0xfcd1b3ddcca92b1e49783769e9bf606112b3f8cf36b96cac05bf44edcf5377e6",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "index": "0x1"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "dep_type": "code"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "header_deps": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      "0x51d199c4060f703344eab3c9b8794e6c60195ae9093986c35dba7c3486224409"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "inputs": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "previous_output": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "tx_hash": "0xa98c57135830e1b91345948df6c4b8870828199a786b26f09f7dec4bc27a73da",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "index": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "since": "0x0"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "outputs": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "capacity": "0x0",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "lock": {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "args": "0x",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">          "hash_type": "data"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        },</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">        "type": null</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "witnesses": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      "0x210000000c0000001d0000000d0000006920616d20612073656372657400000000"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ],</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    "outputs_data": [</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      "0x"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    ]</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">EOF</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ chmod +x runner.rb</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug ./runner.rb ckb-duktape/build/load0 ckb-duktape-template/build/duktape.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Executing: ckb-standalone-debugger/bins/target/release/ckb-debugger --tx-file tx.json --script-group-type lock -i 0 -e input</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0xcf13fa84ff3a615dd496e9ad8647af01078b11ba1c2757889f0a95e2520fdeb9) DEBUG OUTPUT: 0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947c219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd970dd9a8</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 20198757</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 67328, running cycles: 20131429</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>About 20 million cycles are needed for this simple script. As a comparison, we can also implement similar function in pure C:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cat &lt;&lt; EOF &gt; c.c</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "blockchain.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include "ckb_syscalls.h"</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#define MAXIMUM_ARG_SIZE 4096</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#define SCRIPT_SIZE 32768</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#define ERROR_ARGUMENTS_LEN -1</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#define ERROR_ENCODING -2</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#define ERROR_SYSCALL -3</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#define ERROR_SCRIPT_TOO_LONG -21</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#define ERROR_OVERFLOWING -51</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#define ERROR_AMOUNT -52</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">int main() {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  unsigned char script[SCRIPT_SIZE];</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint64_t len = SCRIPT_SIZE;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  int ret = ckb_load_script(script, &amp;len, 0);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (ret != CKB_SUCCESS) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return ERROR_SYSCALL;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (len &gt; SCRIPT_SIZE) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return ERROR_SCRIPT_TOO_LONG;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  mol_seg_t script_seg;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  script_seg.ptr = (uint8_t *)script;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  script_seg.size = len;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (MolReader_Script_verify(&amp;script_seg, false) != MOL_OK) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return ERROR_ENCODING;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  mol_seg_t args_seg = MolReader_Script_get_args(&amp;script_seg);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  mol_seg_t args_bytes_seg = MolReader_Bytes_raw_bytes(&amp;args_seg);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  if (args_bytes_seg.size &gt; MAXIMUM_ARG_SIZE) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    return ERROR_ARGUMENTS_LEN;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  static const char HEXCHARS[] = "0123456789abcdef";</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  char hex[MAXIMUM_ARG_SIZE * 2 + 1];</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  for (size_t i = 0; i &lt; args_bytes_seg.size; i++) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    hex[i * 2] = HEXCHARS[args_bytes_seg.ptr[i] &gt;&gt; 4];</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    hex[i * 2 + 1] = HEXCHARS[args_bytes_seg.ptr[i] &amp; 0xF];</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  hex[args_bytes_seg.size * 2] = '\0';</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  ckb_debug(hex);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return CKB_SUCCESS;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">EOF</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ docker run --rm -it -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20191209 bash</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@57b79063c965:/# cd /code</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@57b79063c965:/code# riscv64-unknown-elf-gcc -O3 -I ckb-duktape/deps/ckb-c-stdlib -I ckb-duktape/deps/molecule c.c -o c -Wl,-static -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-s</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">root@57b79063c965:/code# exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">exit</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug ./runner.rb c ckb-duktape-template/build/duktape.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Executing: ckb-standalone-debugger/bins/target/release/ckb-debugger --tx-file tx.json --script-group-type lock -i 0 -e input</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x9f637b251b36de8e6c8b48a1db2f2dcbb0e7b667de1d3ec02c589a7b680842e1) DEBUG OUTPUT: 32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947c219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd970dd9a8</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 5456</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 878, running cycles: 4578</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>As we shall see here, a similar C script takes only 4578 cycles, which is much less than the JavaScript scripts. Even though our JavaScript script might need consume so less cycles, we can still significantly reduce the cycle consumptions.</p>
<h1>Step 1: Skip Initialization</h1>
<p>Those who are familiar with dynamic languages, would realize that all dynamic language implementations will need an initialization phase to create and properly setup the VM, this could take significant work, costing a lot of cycles. Our first idea comes from this: what if we can save the already initialized state, and reuse that state in later VM executions? The whole state of a CKB VM instance, is 33 registers(32 general purpose registers + PC register) and the memory states. If we can dump those into a separate binary, and recreate the same VM state later, we won't need to do the whole initialization step again and again.</p>
<p>ckb-standalone-debugger actually provides such a dump feature. It adds a new syscall to the VM instance created by the debugger(notice this syscall is useless in production, and will probably never make it into production). When the syscall gets executed, the debugger instance would serialize all VM states, including all registers and memories into a custom-built executable. Later if we instantiate a new VM instance with this generated executable, it will restore all VM states, and the VM will continue to run as if it just returns from the syscall. This way we can do the necessary initialization steps offline via the debugger, then only deploy the generated executable to CKB, all later executions on the executable, can skip the costly initialization part, hence saving a huge amount of cycles.</p>
<p>I have already prepared a duktape <a href="https://github.com/xxuejie/ckb-duktape/blob/d6241938247b402ec56c7af218acfc9049ac753d/c/dump_load0.c" target="_blank" rel="noopener noreferrer">instance</a> which performs the setup, then execute the dump syscall, we can now give this a test:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug ./runner.rb ckb-duktape/build/dump_load0 ckb-duktape-template/build/duktape.js dump0.bin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Executing: ckb-standalone-debugger/bins/target/release/ckb-debugger --tx-file tx.json --script-group-type lock -i 0 -e input -d dump0.bin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0xb5656359cbcd52cfa68e163cdd217657f0cfc533c909d13a1fdd8032f6b4f1f0) DEBUG OUTPUT: 0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947c219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd970dd9a8</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 20199104</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 67352, running cycles: 20131752</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug ./runner.rb dump0.bin ckb-duktape-template/build/duktape.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Executing: ckb-standalone-debugger/bins/target/release/ckb-debugger --tx-file tx.json --script-group-type lock -i 0 -e input</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x51959c6288a1cfba0d7f7dc8c5a90cf9a84bf5b58f1d5ed3b355497d119fba16) DEBUG OUTPUT: 0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947c219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd970dd9a8</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 16249542</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 96998, running cycles: 16152544</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The first command here executes the script as normals, but internally it <a href="https://github.com/xxuejie/ckb-duktape/blob/d6241938247b402ec56c7af218acfc9049ac753d/c/dump_load0.c#L14" target="_blank" rel="noopener noreferrer">calls</a> the dump syscall, resultling in a dumping of the VM state then into <code>dump0.bin</code> executable file. Later when we run CKB VM on <code>dump0.bin</code> directly, we can notice it performs the same action as the above duktape binary, but saves us close to 4 million cycles.</p>
<h1>Step 2: Bytecode Over Source</h1>
<p>Previously, we've been running duktape on CKB VM directly against JavaScript source, this means at runtime, duktape would first need to parse the JavaScript source code, then execute it. The parsing time exists in every single invocation of the same JavaScript file, which could also be a huge waste of cycles. Luckily, duktape provides a <a href="https://github.com/svaarala/duktape/blob/master/doc/bytecode.rst" target="_blank" rel="noopener noreferrer">bytecode</a> format: we can parse the JavaScript source to duktape bytecode format, and only loads and runs the bytecode at runtime. Let's try this now:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ckb-duktape/build/dump_bytecode ckb-duktape-template/build/duktape.js script.bin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug ./runner.rb ckb-duktape/build/dump_load0 script.bin dump0.bin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Executing: ckb-standalone-debugger/bins/target/release/ckb-debugger --tx-file tx.json --script-group-type lock -i 0 -e input -d dump0.bin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0xb5656359cbcd52cfa68e163cdd217657f0cfc533c909d13a1fdd8032f6b4f1f0) DEBUG OUTPUT: 0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947c219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd970dd9a8</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 9239414</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 67352, running cycles: 9172062</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug ./runner.rb dump0.bin script.bin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Executing: ckb-standalone-debugger/bins/target/release/ckb-debugger --tx-file tx.json --script-group-type lock -i 0 -e input</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x51959c6288a1cfba0d7f7dc8c5a90cf9a84bf5b58f1d5ed3b355497d119fba16) DEBUG OUTPUT: 0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947c219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd970dd9a8</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 5289852</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 96998, running cycles: 5192854</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The <a href="https://github.com/xxuejie/ckb-duktape/blob/d6241938247b402ec56c7af218acfc9049ac753d/c/dump_load0.c#L26-L37" target="_blank" rel="noopener noreferrer">dump_load0</a> binary actually supports both duktape bytecode and JavaScript source. It does a runtime check to see if the loaded data here is duktape bytecode or JavaScript source. Here we can see that by combining the previous 2 solutions, we can already shrink the cycle consumption from ~ 20 million to ~ 5 million.</p>
<p>Note that duktape bytecode does come with tradeoffs. It never ensures version compatibility, so different versions of duktape, or even different builds of the same duktape version could use different bytecode format. In a normal environment, this could be a problem, but since here we also ship duktape binary as a smart contract, we can lock the version of duktape binary we are using, ensuring the bytecode always works. Another drawback, and a big surprise to many, is that the bytecode file is in fact usually larger than the original JavaScript source file:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ls -l script.bin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">-rw-rw-r-- 1 ubuntu 7810 Mar 19 05:28 script.bin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ ls -l ckb-duktape-template/build/duktape.js</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">-rw-rw-r-- 1 ubuntu 3551 Mar 19 04:46 ckb-duktape-template/build/duktape.js</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In our example, while the original minimize JavaScript file is about 3.5K, the generated bytecode file is closed to 8K. This brings a tradeoff depending on your use case: do you want smaller file, or less cycle consumption?</p>
<h1>Step 3: Skip Cleanup Work</h1>
<p>CKB VM works slightly different from other environment: it provides you with a fixed 4MB memory segment, and the whole segment will just be thrown away once the code finishes execution. This brings an interesting insight: in a normal environment, you definitely want to cleanup the resource you use before exiting, but in CKB VM environment, this is not necessary, since the whole memory segment will be destroyed all together. As long as you signal the correct response, cleanup steps are actually just a waste of cycles in CKB VM. Given this consideration, I've provided <a href="https://github.com/xxuejie/ckb-duktape/blob/d6241938247b402ec56c7af218acfc9049ac753d/c/dump_load0_nocleanup.c" target="_blank" rel="noopener noreferrer">dump_load0_nocleanup</a> variation, which <a href="https://github.com/xxuejie/ckb-duktape/blob/d6241938247b402ec56c7af218acfc9049ac753d/c/dump_load0_nocleanup.c#L48-L49" target="_blank" rel="noopener noreferrer">does not perform</a> any cleanup work after running the script. Now it is the time to try this final version:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ cd $TOP</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug ./runner.rb ckb-duktape/build/dump_load0_nocleanup script.bin dump0.bin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Executing: ckb-standalone-debugger/bins/target/release/ckb-debugger --tx-file tx.json --script-group-type lock -i 0 -e input -d dump0.bin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x06034ffb00fec553882c6a9c7614333a728828772d3c236a7f8fa6af60669538) DEBUG OUTPUT: 0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947c219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd970dd9a8</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 7856033</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 67348, running cycles: 7788685</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ RUST_LOG=debug ./runner.rb dump0.bin script.bin</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Executing: ckb-standalone-debugger/bins/target/release/ckb-debugger --tx-file tx.json --script-group-type lock -i 0 -e input</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">DEBUG:&lt;unknown&gt;: script group: Byte32(0x0e948e69dd75f2d6676048569073afe4ec2b284144bbe33a6216b13171606d18) DEBUG OUTPUT: 0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947c219351b150b900e50a7039f1e448b844110927e5fd9bd30425806cb8ddff1fd970dd9a8</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Run result: Ok(0)</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Total cycles consumed: 3903352</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">Transfer cycles: 96994, running cycles: 3806358</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With all the solutions combined, we managed to reduce the cycle consumption of a JavaScript based CKB smart contract from 20 million to less than 4 million. This is still far from the C version, which takes less than 5000 cycles. But in many cases, a higher level language like JavaScript will provide superiority over plain old C, and the cycle consumption here might already be good enough.</p>
<h1>Future</h1>
<p>The above are just 3 simple solutions you can levarage, there are very likely to be more way you can use to reduce cycles. One thing to remember, is that you don't have to cater for rules established in an everyday running program. As long as the script satisfies the verification needs on chain, you can employ any techniques to reduce the cycle consumption.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduction to CKB Script Programming 10: Language Choices]]></title>
            <link>https://docs.nervos.org/blog/intro-to-ckb-script-programming-10</link>
            <guid>https://docs.nervos.org/blog/intro-to-ckb-script-programming-10</guid>
            <pubDate>Thu, 09 Apr 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[When crafting CKB, we made the choice to use a generic VM, so it is not bound to any particular programming language. This model certainly has its pros, but it also comes with problems. A question we frequently receive is: what language should I use to program on Nervos CKB? Let's try to answer this question here.]]></description>
            <content:encoded><![CDATA[<p>When crafting CKB, we made the choice to use a generic VM, so it is not bound to any particular programming language. This model certainly has its pros, but it also comes with problems. A question we frequently receive is: what language should I use to program on Nervos CKB? Let's try to answer this question here.</p>
<p>First of all, I have had the belief that each dapp developer should have the freedom to pick their own choice of languages. No blockchain creators know the nuts and bolts better than the dapp developer themselves. No single programming language provides solutions for all kinds of dapps that might sprout. We offer different programming language choices, you can pick based on your needs.</p>
<p>But at the same time, this is also an irresponsible answer! Telling a newcomer that you have many choices to choose from, is like telling them nothing. They will just be overwhelmed by the numerous choices. After all, all they want to do, is pick a language and start experimenting/building. This means while we do offer choices, we will also need to provide recommendations: what will we pick, if we just get started on building a new dapp on CKB?</p>
<p>To make a recommendation, we will first need answers to 2 simple questions:</p>
<ol>
<li>What is your purpose here? Are you just experimenting things on CKB, or are you already tasked to build a production grade dapp?</li>
<li>What do you plan to build? Are you building a normal dapp, or are you creating a new crypto primitives on CKB?</li>
</ol>
<p>The answers to the questions, will affect the choices we suggest here.</p>
<p><strong>NOTE</strong>: the recommendation made here, are only relavant when I write this post(Apr 9, 2020), we are building working on this field, and things might change. I will try to make sure this post is updated, but it is always better to check with us first to see our latest recommendation is, either on <a href="https://discord.gg/AqGTUE9" target="_blank" rel="noopener noreferrer">Discord</a>, or <a href="https://talk.nervos.org/" target="_blank" rel="noopener noreferrer">Nervos Talk</a>.</p>
<p>For people tasked building a production grade dapp, a warning shall be provided above all: no matter what language you pick to build the smart contract part of your dapp, you should do security audit on your smart contracts. Vulnerabilities can only be eliminated via due diligence, no programming languages can help you on this part. With that said, we can now jump to the recommendation part.</p>
<p>Unfortunately, all production level smart contracts on CKB now, are written in pure C. The reason for this, is not C is that suitable language for writing smart contract, but really that when we started out to build CKB, only C provides good enough quality for building the contracts we need. We don't recommend using C to build any smart contract when you have a better choice, but we do admit sometimes C has to be the last resort.</p>
<p>In the meantime, we are busy working on Rust support to prepare Rust for this list. While things are still a little rough today, Rust might be a decent choice for building production level smart contracts on CKB soon. And you can bet on that we will continue to maintain and support building Rust smart contracts on CKB. While personally, I know CKB VM can be leveraged in ways that Rust is having a hard time to keep up, the reality is Rust is a very popular and (in many cases) good enough choice for the blockchain world. We are hoping in the not-so-distant future, maybe in a few months, we can sincerely recommend using Rust to build production level smart contracts on CKB.</p>
<p>While it certainly would not suit all cases, many people might be building smart contracts that:</p>
<ul>
<li>Needs rapid changes or dynamic behaviors;</li>
<li>Are built by not so low-level focused engineers;</li>
<li>Might not be so easily affected by cycle consumptions;</li>
</ul>
<p>For this group of people, JavaScript might also be a decent smart contract choice. We are now evaluating the possibilities if we can perform a round of security audit on duktape, or some other JavaScript engine that is suitable on CKB. While you still need to audit the JavaScript source written by yourself, we can help you ensure that the underlying JavaScript engine you use, will perform in a correct and secure behavior.</p>
<h1>Experimental Languages</h1>
<p>When it comes to experimenting on CKB, you have more freedom to use different other languages. I will divide my recommendation here based on the second question above: the stuff you want to build on CKB.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="cryptographic-primitive-explorer">Cryptographic Primitive Explorer<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-10#cryptographic-primitive-explorer" class="hash-link" aria-label="Direct link to Cryptographic Primitive Explorer" title="Direct link to Cryptographic Primitive Explorer">​</a></h2>
<p>One unique aspect of CKB, is that it helps flourish cryptographic innovations. It's now different from the old days, when you have to wait for a hardfork so someone can include your brand new cryptographic algorithms in a blockchain. With CKB, you can build any cryptographic algorithm, and ship it on chain immediately. You might say: well this is great, but what programming language shall we use here?</p>
<p>If you have checked out <a href="https://github.com/nervosnetwork/ckb-system-scripts" target="_blank" rel="noopener noreferrer">our code</a>, you will noticed that we've taken the <a href="https://github.com/bitcoin-core/secp256k1" target="_blank" rel="noopener noreferrer">secp256k1 C library</a> from the Bitcoin team(huge thanks guys!). So obvious, C is a choice here. But C is hardly the only choice: as mentioned above, we are busy working pushing the frontier here, and we are hoping soon Rust can provide a second choice here. There are already many cryptographic libraries built in Rust, we do want to embrace the whole blockchain community, rather than distancing from it. But there is actually more interesting story here besides C or Rust:</p>
<p>If you dig <a href="https://github.com/bitcoin-core/secp256k1/blob/4f27e344c69c33b4f3f448baa0196b9892287081/src/asm/field_10x26_arm.s" target="_blank" rel="noopener noreferrer">deep</a> <a href="https://github.com/briansmith/ring/blob/00c21e253ba9cd3b66ab41155414b0d0e91b6c95/crypto/poly1305/asm/poly1305-x86_64.pl" target="_blank" rel="noopener noreferrer">enough</a>, most highly used cryptographic libraries uses hand-written assembly to further speed up the code. There is actually <a href="https://cr.yp.to/qhasm/20050129-portable.txt" target="_blank" rel="noopener noreferrer">good reason</a> behind it. Since CKB builds on a real instruction set used by CPU, there's actually no stopping from us to use hand-written RISC-V assembly to further speed up the crypto algorithms. To make it even more existing, we've been paying close attentions to 2 new RISC-V instruction set extension:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=GzZ-8bHsD5s" target="_blank" rel="noopener noreferrer">V: Vector Extension</a></li>
<li><a href="https://github.com/riscv/riscv-bitmanip" target="_blank" rel="noopener noreferrer">B: Bit Manipulation Extension</a></li>
</ul>
<p>We believe those 2 extensions can bring up even closer to the full potential of modern days' CPU architecture. Once they are introduced to CKB, hand-written, assembly based crypto algorithms leveraging them can enjoy an even greater speedups, which is very hard to match via a language such as C or Rust.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="regular-dapp-builder">Regular Dapp Builder<a href="https://docs.nervos.org/blog/intro-to-ckb-script-programming-10#regular-dapp-builder" class="hash-link" aria-label="Direct link to Regular Dapp Builder" title="Direct link to Regular Dapp Builder">​</a></h2>
<p>For experimenting regular dapp logic, you will have a much greater number of choices here: we mentioned JavaScript above, we also have <a href="https://github.com/nervosnetwork/ckb-mruby" target="_blank" rel="noopener noreferrer">Ruby</a> support. Rust will also soon be a viable choice. There is one more language that I particularly want to mention: for some weird unknown reason, <a href="https://assemblyscript.org/" target="_blank" rel="noopener noreferrer">AssemblyScript</a> gets widely used in the blockchain industry. Since we do have WASM integration support now, you can also use AssemblyScript to build smart contracts on CKB. We do want to ensure that your existing knowledge in building smart contracts on other blockchains won't go in vain. Innovation is critical of course, but so is preserving histories.</p>
<h1>Beyond The Horizon</h1>
<p>The advantage on CKB doesn't just stop here. It gets more exciting than this:</p>
<ol>
<li>There are tons of languages that have a pure C VM based implementation, such as Lua, MicroPython;</li>
<li>There are also many languages that can be compiled down to C, we will show a real example later;</li>
<li>LLVM now officially has RISC-V support, there are many languages that target LLVM, such as zig;</li>
<li>We now do have WASM support, there are also languages that target WebAssembly, such as AssemblyScript;</li>
</ol>
<p>So if you are the pioneer kind, you are very welcome to port new languages and make them work on CKB. And they don't have stop as experimental languages. Once they become more mature with people using it, there is nothing stopping us from treating them as production ready languages on CKB. Fundamentally, it all depends on if we know enough about the language to know where we can expect quirks. We are experimenting with new languages all day, and here I can show you my latest attempt:</p>
<h1>ZetZ</h1>
<p>I've been very fascinated by <a href="https://github.com/zetzit/zz" target="_blank" rel="noopener noreferrer">ZetZ</a> these days. It presents a unique feature set that suits CKB VM perfectly:</p>
<ul>
<li>Compiled to C, so we can then use GCC to compile it to RISC-V binaries</li>
<li>Encourages stack usage without dynamic memory allocation</li>
<li>Leverages an <a href="https://github.com/Z3Prover/z3" target="_blank" rel="noopener noreferrer">SMT solver</a> to verify code execution</li>
</ul>
<p>This basically provides an immediate to use language that suits blockchain smart contract extremely well: on the lower level, a C compiler helps you generate code that is both small and efficient; on the higher level, a theorem prover helps you check code logic to make sure they make sense. In addition, this is not some sort of pure hobby project, it is developed together with a real <a href="https://github.com/devguardio/carrier" target="_blank" rel="noopener noreferrer">usage</a> in an IoT system with a lot of cryptographic code involved, much like how we would use it in blockchains.</p>
<p>Here our old carrot example in ZetZ:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">using &lt;ckb_syscalls.h&gt; as ckb</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">using &lt;string.h&gt;::{memcmp};</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">fn load_data(u64 index, u8 mut * buffer) -&gt; int</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">   where len(buffer) &gt;= 6 {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  u64 mut l = 6;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  int ret = as&lt;int&gt;ckb::ckb_load_cell_data(buffer, &amp;l, 0, index, 2);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return ret;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">export fn main () -&gt; int {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  u64 index = 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  while true {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    u8 buffer[6];</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    int ret = load_data(index, buffer);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    if ret == 1 {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      break;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    if memcmp(buffer, "carrot", 6) == 0 {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      return -1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    index++;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You don't have to be able to understand anything here. However, if you have a little experience with C, that <code>where len(buffer) &gt;= 6</code> will immediately catch your attention: ZetZ uses theorem prover to ensure all calling to the <code>load_data</code> function shall provide a buffer that is at least 6 bytes long. If we change the buffer size in the main function to something less than 6, an error will immediately be generated when we build the source code:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">$ zz build</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> [ERROR] unproven callsite assert for infix expression</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  --&gt; /home/ubuntu/code/ckb-zz-demo/src/main.zz:15:25</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">   |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">15 |     int ret = load_data(index, buffer);␊</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">   |                         ^------------^</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">   |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">   = in this callsite</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> --&gt; /home/ubuntu/code/ckb-zz-demo/src/main.zz:5:22</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">5 |    where len(buffer) &gt;= 6 {␊</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |                      ^^</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  = function call requires these conditions</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> --&gt; /home/ubuntu/code/ckb-zz-demo/src/main.zz:4:1</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">4 | fn load_data(u64 index, u8 mut * buffer) -&gt; int␊</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  | ...</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">9 | }␊</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  | ^</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  = for this function</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> --&gt; /home/ubuntu/code/ckb-zz-demo/src/main.zz:5:22</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">5 |    where len(buffer) &gt;= 6 {␊</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |                      ^^</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  = for infix expression |0| = false</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> --&gt; /home/ubuntu/code/ckb-zz-demo/src/main.zz:5:14</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">5 |    where len(buffer) &gt;= 6 {␊</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |              ^-----^</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  = for literal 3 |0| = 0x3</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain"> --&gt; /home/ubuntu/code/ckb-zz-demo/src/main.zz:5:25</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">5 |    where len(buffer) &gt;= 6 {␊</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |                         ^</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  = for literal 6 |0| = 0x6</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  --&gt; /home/ubuntu/code/ckb-zz-demo/src/main.zz:15:25</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">   |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">15 |     int ret = load_data(index, buffer);␊</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">   |                         ^------------^</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">   |</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">   = last callsite</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You can see here that ZetZ knows that we are passing a buffer of 3 bytes to a function which requires a buffer of at least 6 bytes. The build phase results in an error.</p>
<p>On the other hand, the final generated code, when cleaned a bit, looks exactly like how we would write this by hand in C:</p>
<div class="codeBlockContainer_APcc theme-code-block" style="--prism-color:var(--code-plain);--prism-background-color:var(--surface-02)"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:var(--code-plain);background-color:var(--surface-02)"><code class="codeBlockLines_p187"><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;stdbool.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;stddef.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;stdint.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">static int ckb_zz_demo_main_load_data(uint64_t const index,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                                      uint8_t* const buffer);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;string.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">int __attribute__((visibility("default"))) ckb_zz_demo_main_main();</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">#include &lt;ckb_syscalls.h&gt;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">static int ckb_zz_demo_main_load_data(uint64_t const index,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                                      uint8_t* const buffer);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">int main() {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint64_t const index = 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  while (true) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    uint8_t const buffer[6];</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    int const ret = ckb_zz_demo_main_load_data(index, buffer);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    if ((ret == 1)) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      break;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    if ((memcmp(buffer, "carrot", 6) == 0)) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">      return -1;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">    (index++);</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  }</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return 0;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">static int ckb_zz_demo_main_load_data(uint64_t const index,</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">                                      uint8_t* const buffer) {</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  uint64_t l = 6;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  int const ret = (int)(ckb_load_cell_data(buffer, (&amp;l), 0, index, 2));</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">  return ret;</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain">}</span><br></span><span class="token-line" style="color:var(--code-plain)"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_FhaS" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_phi_"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_FfTR"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>No prover checking code is included in the final C code here, it is just how a plain C implementation would look like. We are not paying any runtime cost here.</p>
<p>This example here only demostrates a small benefit of ZetZ, while the theorem prover in ZetZ can definitely do more sophisticated checking. The language is still in its infancy phase, I don't know how the future would look like, but this is definitely something I'd like to keep an eye on.</p>
<h1>Recap</h1>
<p>I hope you won't treat me as a ZetZ zealot now. It really is just one example I'm playing with now. What I'm trying to say here, is that if you have any particular language you love, or discover anything that might be useful for your dapp. There really is nothing that prevents you from porting that to CKB. We really want to put the freedom, back to all the awesome developers out there. And if you have built something that proves to be useful, our <a href="https://www.nervos.org/grants/" target="_blank" rel="noopener noreferrer">grant</a> program is awaiting for your submission.</p>]]></content:encoded>
        </item>
    </channel>
</rss>