Understand the programmability of CKB from Bitcoin application programming

Original author: Ajian

Summary

Understanding the programmability of a system requires us to identify the structural features of the system. The exploration of Bitcoin Script-based application programming helps us understand the basic structure of CKB Cell and its programming paradigm. Not only that, but it breaks down the programming components of the CKB into the right pieces and helps us understand the programmability gains that each part brings.

I. Introduction

“Programmability” is a dimension that people often take when comparing blockchain systems. However, there is often disagreement about how programmability is described. A common expression is “XX blockchain supports Turing-complete programming languages”, or, “XX blockchain supports general-purpose programming”, which is intended to indicate that the “XX blockchain” here has strong programmability. There is some truth to the implication of these statements: systems that support Turing-complete programming are generally easier to program than those that don’t. However, there are many aspects to the structural characteristics of a smart contract system, and this statement touches on only one of them, so it is not enough to be understood in sufficient depth by virtue of the fact that developers are not guided by it, and ordinary users cannot be relied upon to distinguish fraud.

Structural features of a smart contract system include:

  • The basic form of state expression (contract) (account vs. trade output)
  • Whether or not arbitrary computation is allowed to be programmed (this is what the term “Turing-complete” is about)
  • Does the execution process create new data, or does it just pass out booleans? (Compute vs. Validation)
  • Whether or not to allow additional states to be recorded within the contract
  • Whether a contract has access to the state of another contract when it is executed

Therefore, in addition to “programmable arbitrary computation”, there are at least four characteristics that affect the programmability of a smart contract system. It can even be said that these other features are more important, because they determine at a deeper level what is easy to achieve and what is difficult to achieve; What is a more economical implementation and what is a less efficient implementation.

For example, Ethereum is often cited as an example of good programmability, but the basic form of state expression on Ethereum is an account, which makes it difficult to program peer-to-peer contracts (e.g., payment gateways, one-to-one betting contracts) — not absolutely impossible, just thankless. It’s not uncommon for the Ethereum ecosystem to try to implement a payment channel/state channel, and there have been a lot of theoretical discussions, but these projects don’t seem to be active anymore — and this obviously can’t be blamed on the lack of effort on the part of developers. It is no coincidence that projects active on Ethereum today are taking the form of “pools” rather than “peer-to-peer contracts”. Similarly, people may be happy with Ethereum’s programmability, but the account model is inherently deficient in achieving “account abstraction” (which can also be understood as a generalization of the wallet concept).

In the same way, exploring the programmability of CKB also requires us to understand the structural characteristics of the CKB smart contract system in these aspects. What we already know is that CKB allows arbitrary calculations to be programmed, allows additional state to be recorded within a contract, and allows one contract to access the state of another contract when executed. However, the form of the contract is the output of a transaction (called a “cell”), which makes it fundamentally different from Ethereum. Therefore, an understanding of the Ethereum smart contract system and the contract instances within it does not help us understand how CKB implements these structural features, nor does it help us understand the programmability of CKB.

Fortunately, smart contracts on Bitcoin seem to provide the best basis for understanding the programmability of CKB. This is not only because the basic form of Bitcoin’s state representation is also the output of transactions (called “UTXOs”), but also because, with the help of a concept proposed by the Bitcoin community called “covenants”, we can understand why CKB has these structural characteristics, and appropriately break down the final effect into several parts, identifying the programmability gains that each of them brings.

II. CKB v.s. BTC: What’s More?

(1) Basic structure

As the basic form of Bitcoin’s state representation, Bitcoin’s UTXO (“Unspent Transaction Output”) has two fields:

  1. The amount, in Satoshi, indicates the value of Bitcoin possessed by the UTXO;
  2. The script public key, also known as the lock script, represents the conditions that need to be met to spend the funds, that is, the smart contract program that sets the conditions for unlocking the funds.

Compared to the smart contract systems that came later, Bitcoin Script is quite limited:

  • It does not allow programming arbitrary calculations; There are only a few practical calculations that can be used for verification (signature checking, pre-hash checking, time checking)
  • It does not allow additional states to be recorded within the contract; (For example, you can’t use a script to limit the proportional/maximum amount of money spent at a time; There’s also no way to hide a token in it)
  • It also does not allow access to the state of another contract at the time of execution (each script is a separate universe and does not depend on each other).

This kind of scripting, while limited, doesn’t lack the ability to program amazing applications, and it’s the foundation of our exploration of CKB programmability. There will be a section later on that that will introduce two examples of Bitcoin Script programming.

In contrast, the CKB’s state unit is called a “cell” and has four fields:

  1. Capacity, similar to the amount of UTXO, expresses the amount of space that the cell can occupy, measured in bytes.
  2. Lock, similar to the UTXO script public key, defines the ownership of the cell; Only when the provided data can pass through the lock can the cell be “updated” (or the cell can be released and the capacity can be used to mint new cells);
  3. Data, data, arbitrary data, the volume of which is limited by Capacity;
  4. Type, an optional script that sets conditions for updating Data.

In addition, Lock and Type can be programmed for arbitrary calculations. You can program any signature verification algorithm, you can program any hash algorithm for preimage checking, and so on.

It’s easy for readers to see how programmability Cell improves over UTXOs:

  • Cells can be programmed with arbitrary calculations, rather than just a few specific calculations; Its ownership verification will be more flexible;
  • Because of the Data and Type fields, the cell can record additional states; This allows the cell to carry what is known as a “UDT” (user-defined token).

Combined with the “transaction output” structure of the cell itself, the benefits of these two points in themselves are very, very significant, but from the above description alone, we do not know how the cell achieves “one contract accesses the state of another contract at runtime”. To do this, we need to draw on a concept that has been discussed for a long time in the Bitcoin community: “covenants”.

(2) Limitations and introspection

The original purpose of a restriction clause is to limit where a sum of money can be spent. On current Bitcoin (where no restrictions have been proposed), a single amount of money, once unlocked, can be spent anywhere (it can be paid to an arbitrary script public key). But the idea of the restriction clause is that it can be spent in a way that limits it to certain places, for example, a certain UTXO will only be spent by a certain transaction, so that even if someone can provide a signature for the UTXO, where it can be spent has already been determined by that transaction. This may seem a bit strange, but it can lead to some interesting applications, which will be covered in a section later. Importantly, it is key to our further understanding of CKB programmability.

Rusty Russell rightly points out that a restriction can be understood as an “introspection” ability to trade, i.e., when a UTXO A is spent by a transaction B, a script operator can read some (or all) of transaction B and then check that they match the parameters pre-requested by the script. For example, whether the script public key for the first output of transaction A matches what is required by UTXO A’s script public key (this is what the restriction originally meant).

The astute reader will realize that with complete introspection, the input of one transaction can read the state of another input of the same transaction, which enables the ability of one contract to access the state of another contract at runtime. In fact, that’s exactly how CKB Cell was designed.

Based on this, we can divide this complete introspective capacity into four scenarios:

  • Lock reads other (input and output) locks
  • Lock reads the Type (as well as Data) of the other (input and output)
  • Type reads other (input and output) locks
  • Type reads the Type (and Data) of the other (input and output)

This allows us to analyze the role of each part’s introspective capabilities in different use cases under certain assumptions (the division of functions between Lock and Type), i.e., the programmability gain that each part brings to us.

In the following two sections, we’ll look at the current (and not yet proposed) programming of Bitcoin Script, and the probable functionality that the proposed restriction is expected to achieve, so as to give a concrete understanding of how CKB Cell can be programmed and done better.

III. Bitcoin Script Programming

In this section, we will use “Lightning Channel/Lightning Network” and “Caution Journal Contract (DLC)” as examples of application programming based on Bitcoin Script. Before we get into that, let’s take two things into it.

(1) OP_IF and “Commitment Deals”

The first concept is the flow control opcode in Bitcoin Script, such as: OP_IF, OP_ELSE. These opcodes are no different from IF in computer programming, and their purpose is to execute different statements based on different inputs. In the context of Bitcoin Script, this means that we can set multiple unlocking paths for funds; Combined with the timelock feature, this means that we can assign priority to actions.

Take the famous “Hash Timelock Contract (HTLC)” as an example, which translates into vernacular:

Alternatively, Bob could reveal the preimage behind a hash H and give his own signature, which would cost the money
Or, Alice can spend the money with her own signature after a certain period of T

This “or … or …” The effect is achieved through the process control opcode.

The most prominent advantage of > HTLC is that it can bundle multiple operations together and atomize them. For example, if Alice wants to exchange BTC for CKB with Bob, then Bob can first give a hash value and create an HTLC on the Nervos Network. Alice then creates an HTLC on Bitcoin that uses the same hash. Alternatively, Bob takes the BTC paid by Alice on Bitcoin, while also revealing the preimage, allowing Alice to withdraw CKB on the Nervos Network. Either way, Bob doesn’t reveal the original image, both contracts expire, and both Alice and Bob can get back the money they invested.

After the activation of the Taproot soft fork, this multi-unlock path feature is further enhanced by the introduction of MAST (Merkle Abstract Syntax Tree): we can turn an unlock path into a leaf on the Merkle tree, each leaf is independent, so there is no longer a need to use such a flow control opcode; Also, because one path is revealed without exposing the others, we can add a larger number of unlock paths to an output without having to worry about economics.

The second concept is “commitment trading”. The idea of a committed transaction is that, in some cases, a valid Bitcoin transaction, even if it is not confirmed by the blockchain, is just as real and binding.

For example, Alice and Bob share a UTXO that requires both of them to be signed to spend. At this point, Alice constructs a transaction to spend it, transferring 60% of its value to Bob and the rest to herself; Alice provides her own signature for the transaction, which is then sent to Bob. Well, for Bob, it doesn’t have to be broadcast to the Bitcoin network, and it doesn’t have to be confirmed by the blockchain, and the payment effect of this transaction is also real and credible. Because Alice can’t spend the UTXO on her own (and therefore can’t spend it repeatedly), and because the signature provided by Alice is valid, Bob can always add his signature and broadcast the transaction to honor the payment. In other words, Alice provided Bob with a “credible commitment” through this valid (off-chain) transaction.

Committed transactions are a core concept of Bitcoin application programming. As mentioned earlier, Bitcoin’s contract is verification-based, stateless, and does not allow cross-access; However, if the contract does not carry states, where are those states stored, and how can the contract safely move forward (change state)? Commitment transactions give a straightforward answer: the state of the contract can be expressed in the form of transactions, so that the participants of the contract can save the state themselves without having to display it on the blockchain; The problem of changing the state of the contract can also be transformed into the problem of how to safely update the committed transaction; In addition, if we are concerned about the dangers of entering a contract (for example, entering a contract that requires both parties to sign in order to spend, and there is a risk that the other party will not respond and get stuck), then simply generating a commitment transaction that costs the contract in advance and getting a signature can mitigate the risk and eliminate trust in other participants.

(2) Lightning channel and lightning network

A lightning channel is a one-to-one contract in which two parties can pay each other an unlimited number of times without having any one payment confirmed by the blockchain. As you might expect, it uses commitment trading.

In the section explaining “Committed Transactions”, we have already introduced a payment channel. However, this kind of contract, which only leverages 2-of-2 multisig, can only enable one-way payments. That is, either Alice always pays Bob, or Bob always pays Alice until he uses up his balance in the contract. If it’s a two-way payment, it means that after a status update, one party may have less balance than before, but the TA has the last committed transaction signed by the other party - what can be done to stop the TA from broadcasting the old promise and the TA from only the most recent commitment transaction?

The solution to this problem with the lightning channel is called “LN-Penalty”. Now, let’s say Alice and Bob each have 5 BTC in a channel; Now Alice wants to pay Bob 1 BTC, so she signs the promised transaction and sends it to Bob:

Enter #0 and 10 BTC:
Alie-Bob 2-of-2 multi-signature output (i.e. channel contract)

Output #0 , 4 BTC:
Alice single-signature

Output #1 , 6 BTC:
or
Alice-Bob federated ephemeral public key #1 single-signature
or
T 1 timelock, Bob single-signed

Bob also signs a commitment (which corresponds to the above transaction) and sends it to Alice:

Enter #0 and 10 BTC:
Alie-Bob 2-of-2 multi-signature output (i.e. channel contract)

Output #0 , 6 BTC:
Bob single-signed

Output #1 , 4 BTC:
or
Bob-Alice federated ephemeral public key #1 single-signature
or
T 1 timelock, Alice single-signed

The trick here lies in this “joint temporary public key”, which is generated using one of her own public keys and a public key provided by the other party, for example, Alice-Bob joint temporary public key, which is obtained by Alice using one of her own public keys and a public key provided by Bob, multiplying each by a hash value. When such a public key is generated, no one knows its private key. However, if Bob tells Alice the private key of the public key he provided, Alice can calculate the private key of the federated temporary public key. - This is the key to the fact that the Lightning Channel can “undo” the old state.

The next time the two parties want to update the channel status (initiate a payment), the two parties exchange the private key of the temporary public key given to each other in the previous round. In this way, participants no longer dare to broadcast the last promised transaction they received: the output of this promised transaction assigning value to their own party has two paths, and the private key of the temporary public key path is already known to the other party; So once the old commitment transaction is broadcast, the other party can immediately use this joint temporary private key to take all the funds in this output. - This is what “LN-Penalty” means.

Specifically, the order of interaction is as follows: the party initiating the payment first requests a new temporary public key from the other party, and then constructs a new commitment transaction and hands it to the other party; The party who got the promised transaction revealed to the other party the private key of the temporary public key he gave in the previous round. This sequence of interactions ensures that participants always get a new commitment transaction before invalidating the commitment transaction they received in the previous round, and is therefore trustless.

In summary, the key designs of the lightning channel are:

  1. Both parties always use commitment transactions to express the state within the contract, and the change in the amount to express the payment;
  2. Commitment transactions always cost the same input (input that requires both parties to provide signatures at the same time), so all commitment transactions are competing with each other, and only one can be confirmed by the blockchain.
  3. The two participants are not signing the same commitment transaction (although they are paired); And what they sign is always a transaction that is more favorable to themselves, in other words, the promised transaction that the participants receive is always unfavorable to themselves;
  4. The disadvantage of this is that the output that assigns value to itself has two unlocking paths: one path can be unlocked with its own signature, but it needs to wait for a while; The other path uses the other party’s public key, which is protected only if one of its temporary private keys is not exposed.
  5. In each payment, both parties exchange the temporary private key used by the other party in the previous round with a new commitment transaction, so that the party who handed over the temporary private key no longer dares to broadcast the old commitment transaction, so it “cancels” the previous commitment transaction and updates the status of the contract; (Actually, these promised transactions are all valid transactions and can be broadcast to the blockchain, but the participants are forced to be punished and dare not broadcast anymore)
  6. Either party can withdraw from the contract at any time with a commitment signed by the other party; However, if both parties are willing to cooperate, they can sign a new deal so that both parties can get their money back immediately.

Finally, because HTLC can also be placed in a committed transaction, the Lightning channel can also forward payments. Assuming that Alice can find a path consisting of lightning channels connecting before and after to reach Daniel, then trustless multi-hop payments can be achieved without opening a channel with Daniel. This is the Lightning Network:

Alice – HTLC --> Bob – HTLC --> Carol – HTLC --> Daniel
Alice < – Preimage – Bob < – Preimage – Carol < – Preimage – Daniel

When Alice finds such a path and wants to pay Daniel, she asks Daniel for a hash to construct an HTLC for Bob, and prompts Bob to forward a message to Carol and provide the same HTLC; The message prompts Carol to forward the message to Daniel and provide the same HTLC. When the news reaches Daniel, he reveals the preimage to Carol, which gives him the value of HTLC and updates the state of the contract. Carol did the same, getting paid by Bob and updating the channel status; Finally, Bob reveals the preimage to Alice and updates the status. Due to the nature of HTLC, this chain of payments either succeeds or fails together, and as such, it is trustless.

The Lightning Network is made up of one channel after another, each of which is independent of each other. This means that Alice only needs to know what’s happening in her channel with Bob, regardless of how many interactions have taken place in other people’s channels, what currency those interactions use, or even whether they’re actually using the channel.

The scalability of the Lightning Network is not only reflected in the fact that the payment speed within a Lightning Channel is only limited by the investment of hardware resources by both parties, but also that due to the decentralized storage of state, a single node can leverage the maximum leverage with the lowest cost.

(3) Be cautious of journal contracts

The Cautionary Journaling Contract (DLC) uses a cryptographic technique called “adaptor signature” that allows Bitcoin Script to program financial contracts that depend on external events.

Adapter signatures allow a signature to become a valid signature only after a private key is added. Take the example of a Schnorr signature, where the standard form of a Schnorr signature is (R, s), where:

R = r.G

The nonce value r used for the signature is multiplied by the elliptic curve generation point, which can also be said to be the public key of r

s = r + Hash(R || m || P) * p

p is the signing private key, and P is the public key

验证签名即验证 s.G = r.G + Hash(R || m || P) * p.G = R + Hash(R || m || P) * PK

Let’s say I give a pair of data (R, s’) where:

R = R 1 + R 2 = r 1.G + r 2.G
s’ = r 1 + Hash(R || m || P) * p

Obviously, this is not a valid Schnorr signature, and it does not pass the validation formula, but I can prove to the verifier that it can be a valid signature by simply knowing the private key of R 2, r 2:

s’. G + R 2 = R 1 + Hash(R || m || P) * P + R 2 = R + Hash(R || m || P) * P

Adapter signatures make the validity of a signature dependent on a secret data and is verifiable. But what does this have to do with financial contracts?

Let’s say Alice and Bob want to bet on the outcome of a ball game. Alice and Bob bet on the Green Goblin and Alina to win, respectively, with a bet of 1 BTC. In addition, Carol, a football review website, promised to use a nonce R_c to post a signed s_c_i of the results when the results of the game were announced.

As can be seen, there are three possible outcomes (so there are 3 possibilities for Carol’s signature):

  • Green Goblin wins, Alice wins 1 BTC

  • Alina wins, and Bob wins 1 BTC

  • Tie, the funds of the two return the same way

To do this, the two create a commitment deal for each outcome. For example, the commitment transaction they created for the first outcome would look like this:

Enter #0 , 2 BTC:
Alie-Bob 2-of-2 multi-signature output (i.e. bet contract)

Output #0 , 2 BTC:
Alice single-signature

However, instead of (R, s), the signature Alice and Bob created for this transaction is an adapter signature (R, s’); In other words, the signatures given to each other by both parties cannot be used directly to unlock the contract, but must reveal a secret value. This secret value is the preimage of s_c_ 1.G, which is Carol’s signature! Since Carol’s signature nonce value has been determined (R_c), s_c_ 1.G can be constructed (s_c_ 1.G = R_c + Hash(R_c ||). ‘Green Goblin wins’ || PK_c) * PK_c)。

When the results are revealed, assuming that the Green Goblin wins, Carol will issue a signature (R_c, s_c_ 1), so that either Alice or Bob can complete the opponent’s adapter signature and add their own signature to make the above transaction a valid transaction, and broadcast it to the network to trigger the settlement effect. But if the Green Goblin doesn’t win, Carol won’t post s_c_ 1, and the commitment deal won’t be a valid deal.

And so on, as are the other two trades. In this way, Alice and Bob make the execution of the contract dependent on external events (to be precise, on the assertor machine’s broadcast of external events, in the form of a signature) without having to trust the counterparty. Large and small financial contracts, such as futures and options, can be implemented in this way.

Compared with other forms of implementation, the most important feature of the cautious log contract is its privacy: (1) Alice and Bob do not need to tell Carol that they are using Carol’s data, which does not affect the execution of the contract at all; (2) On-chain observers (including Carol) will not be able to determine which website they are using through Alice and Bob’s contract execution, or even that their contract is a betting contract (not a lightning channel).

IV. Introduction to the Application of Restrictions

(a) OP_CTV and congestion control

The developers of the Bitcoin community have made a number of proposals that can be classified as restrictive clauses. At the moment, one of the most well-known proposals is OP_CHECKTEMPLATEVERIFY (OP_CTV), which is popular with the Bitcoin community for its simplicity but flexibility with its simple concept. The idea of OP_CTV is to commit a hash in the script to constrain that the funds can only be spent by the transactions represented by this hash; This hash promises the output of the transaction and most of the fields, but not the input of the transaction, only the number of inputs.

“Congestion Control” is a good example of how OP_CTV can be demonstrated. Its basic use case is to help a large number of users exit from an exchange (an environment that requires trust) into a pool; Since this pool uses OP_CTV to plan how it will be spent in the future, it guarantees that users can exit the pool trustlessly, without the help of anyone; And because this pool only behaves as a UTXO, it avoids paying a lot of fees when demand for on-chain transactions is high (from n outputs to 1 output; also reduced from n transactions to 1 transaction). Users in the pool can wait for an opportunity to exit the pool.

Let’s say Alice, Bob, and Carol want to withdraw 5 BTC, 3 BTC, and 2 BTC from the exchange, respectively. Then the exchange can make an output of 10 BTC with 3 OP_CTV branches. Let’s say Alice wants to withdraw money, she can use branch 1; The transaction represented by the hash value used by the OP_CTV of the branch will form two outputs, one of which is to allocate 5 BTC to Alice; The other output, in turn, is a pool, which also uses OP_CTV to commit to a transaction, allowing Bob to withdraw only 3 BTC and send the remaining 2 BTC to Carol.

It’s the same thing if Bob or Carol wants to withdraw money. When withdrawing money, they will only be able to use transactions that can pass the corresponding OP_CTV check, i.e. they will only be able to pay the corresponding amount to themselves, and will not be able to withdraw money arbitrarily; The remaining funds will go into a pool with an OP_CTV lock, thus guaranteeing that the remaining users can be placed out of the pool trustlessly, regardless of the order in which they are withdrawn.

In the abstract, the role of OP_CTV here is to plan the path to the end of the life of the contract for the contract, so that the pool contract here can maintain the attribute of trustless exit no matter which path it takes or which state it goes.

There is also a very interesting use of this OP_CTV: “one-way payment channel that is hidden but not revealed”. Suppose Alice forms such a pool of funds and guarantees that the funds can be trustlessly withdrawn into an output with the following script:

or, Alice and Bob spend it together
or, after a while, Alice can spend it on her own

If Alice hadn’t revealed it to Bob, Bob wouldn’t have known that such an output existed; Once Alice reveals it to Bob, Bob can use the output as a time-sensitive, one-way payment channel that Alice can use to pay Bob immediately without having to wait for confirmation from the blockchain. Bob simply asks Alice to put his commitment transaction on-chain before Alice can spend it on his own.

(b) OP_Vault and safe

OP_VAULT is a proposal for a restrictive clause specifically designed to construct “vaults”.

The Vault contract is designed to be a more secure and advanced form of self-custody. Although the current multi-signature contract can avoid a single point of failure for a single private key, if an attacker does obtain a threshold number of private keys, the owner of the wallet is helpless. Vault wants to impose a single spending limit on your funds; At the same time, when withdrawing money from it using the regular route, the withdrawal operation will enforce a waiting period; And during the waiting period, the withdrawal operation can be interrupted by the operation of emergency recovery of the wallet. Even if such a contract is breached, the owner of the wallet can initiate a counter-operation (using the emergency recovery branch).

Theoretically, OP_CTV can also program such a contract, but there are many inconveniences, one of which is the commission: while committing to the transaction, it also promises the fee that the transaction will pay. Given the purpose of this contract, the time interval between setting up the contract and withdrawing money must be very long, so it is almost impossible to predict the appropriate commission. Although OP_CTV does not limit the inputs, so the fee can be increased by increasing the input, the input provided will all become the commission, so it is unrealistic; Another way is CPFP, which is to provide a commission on new transactions by spending the withdrawn funds. In addition, the use of OP_CTV means that such a Vault contract cannot be withdrawn in bulk (and certainly cannot be restored in bulk).

The OP_VAULT proposal attempts to address these issues by proposing new opcodes (OP_VAULT and OP_UNVAULT). OP_UNVAULT is designed for batch resiliency, so we won’t mention it for now. OP_VAULT behaves like this: when we put it on a branch of the script tree, it can be used to commit to a usable opcode (e.g. OP_CTV) without specific parameters; When spending this branch, transactions can be passed in specific parameters, but not other branches. As a result, it doesn’t have to set a preset fee, and it can be set when the branch is spent; Assuming that the branch also has a timelock, then it will enforce a timelock; Finally, since you can only change the branch you are on, and no other branch of the new script tree (including the emergency recovery branch) will be changed, we are allowed to interrupt such withdrawals.

In addition, two points are worth mentioning: (1) the OP_VAULT opcode behaves similarly to another restriction proposal: OP_TLUV; Jeremy Rubin rightly points out that this has given rise to the concept of “computation” to a certain extent: OP_TLUV/OP_VAULT first promises an opcode to allow the consumer to update the entire script tree leaf by passing parameters to the opcode with a new transaction; It’s no longer about “validating incoming data based on certain criteria”, it’s about “generating new meaningful data based on incoming data”, although the computation it can enable is limited.

(2) The full OP_VAULT proposal also makes use of some of the proposals on the mempool policy (e.g., v3 transactions) to achieve better results. This reminds us that the meaning of “programming” can be broader than we think. (A similar example is Open Transaction in the Nervos Network.) )

V. Understanding CKB

In the above two sections, we describe how we can script interesting applications on a more constrained structure (Bitcoin UTXO); Proposals to try to add introspection to such a structure were also presented.

While UTXOs have the ability to program these applications, it’s easy for readers to spot their shortcomings or areas that can be optimized, such as:

  • In LN-Punishment, channel participants must save each past committed transaction and the corresponding penalty secret value in order to deal with the opponent’s fraud, which constitutes a storage burden. If there is a mechanism that ensures that only the most recent commitment transaction will take effect, and the old commitment transaction will not, it can eliminate this burden, and it can also eliminate the problem of nodes being accidentally penalized for mistakenly putting an older commitment transaction on-chain.
  • In the DLC, it is assumed that there are many possible outcomes of the event, and there are many signatures that both parties have to generate and hand over to each other in advance, which is also a huge burden; In addition, the income of the DLC contract is directly bound to the public key, so its position is not easy to transfer, is there a way to transfer the position of the contract?

In fact, the Bitcoin community has come up with answers to these questions, basically related to a Sighash proposal (BIP-118 AnyPrevOut).

However, if we were programming on CKB, BIP-118 would be available now (such Sighash tags could be simulated with the ability to introspectively and purposefully verify signatures).

By learning to program Bitcoin, we not only know how they can be programmed in the format “Transaction Output” (what can be programmed in CKB), but also how to improve these applications (and how we can use the capabilities of CKB to improve them if we program them on CKB). For CKB developers, programming based on Bitcoin Script can be used as a learning material, or even a shortcut.

Below, let’s analyze the programmability of each module of CKB programming one by one. Let’s not consider introspection for now.

(1) Programmable arbitrarily calculated lock

As mentioned above, UTXOs cannot be programmed to arbitrarily compute. Lock, on the other hand, means that Lock can program everything (prior to the restriction deployment) based on UTXO, including but not limited to the Lightning Channel and DLC mentioned above.

In addition, this ability to verify arbitrary computation also makes Lock more flexible than UTXO in terms of authentication methods. For example, we can implement a lightning channel on the CKB where one party signs ECDSA and the other party uses RSA.

In fact, this is one of the first areas that people started exploring at CKB: using this flexible authentication capability in the user’s self-custody to enable what is known as “account abstraction” – the authorization of transaction validity and the restoration of control are very flexible and almost unlimited. In principle, this is a combination of “multiple spend branches” and “arbitrary authentication methods”. Examples of implementations are: joyid wallet, UniPass.

In addition, Lock can implement eltoo proposals, enabling a lightning channel that only needs to keep the latest committed transaction (in fact, eltoo can simplify all peer-to-peer contracts).

(2) Programmable arbitrarily calculated Type

As mentioned above, one of the big uses of Type is to program UDTs. Combined with Lock, this means that we can implement UDT-based lightning channels (and other types of contracts).

In fact, the split between Lock and Type can be seen as a security upgrade: Lock focuses on implementing custody methods or contractual agreements, while Type focuses on defining UDTs.

In addition, the ability to start checks based on UDT definitions also enables UDT to participate in contracts in a similar way to CKB (UDT is first-class citizen).

For example, the author once proposed a protocol to implement trustless NFT-backed lending on Bitcoin. The key to such a protocol is a committed transaction where the value of the input is less than the value of the output (so it is not yet a valid transaction), but once sufficient input can be provided for the transaction, it is a valid transaction: once the lender is able to repay, the lender cannot take the staked NFT for himself. However, the trustlessness of this commitment transaction is based on the transaction checking the amount of input and output, so the lender can only use Bitcoin to repay the loan - even if both the lender and the lender are willing to accept another currency (such as USDT issued under the RGB protocol), the Bitcoin commitment transaction does not guarantee that the lender will get their NFT back as long as the lender returns the full amount of USDT, because the Bitcoin transaction has no idea the status of USDT! (Revision: In other words, it is not possible to construct a committed transaction conditional on USDT repayment.) )

If we are able to initiate a check based on the definition of UDT, we will be able to get the lender to sign another committed transaction that will allow the lender to use USDT to repay the loan. The transaction will check the amount of USDT entered and the amount of USDT out, giving users trustless repayment with USDT.

Amendment: Assuming that the NFT used as collateral and the token used for repayment are issued using the same protocol (such as RGB), then the problem here can be solved, and we can construct a commitment transaction according to the RGB protocol, so that the state transition and repayment of the NFT can occur simultaneously (two state transitions are bound with transactions within the RGB protocol). However, because RGB transactions also rely on Bitcoin transactions, the construction of commitment transactions here will be somewhat difficult. All in all, although the problem can be solved, it can’t be done Token is first-class citizen.

Next, let’s consider introspection.

(3) Lock reads other locks

This means the full range of programming possibilities on Bitcoin UTXOs after the proposed restriction is implemented. This includes the Vault contracts mentioned above, as well as OP_CTV-based applications (e.g., congestion control).

XueJie once mentioned a very interesting example: you can implement a collection account cell on CKB, when using this kind of cell as the input of the transaction, if the output cell (the cell using the same lock) has more capacity, then the input does not need to provide a signature and does not affect the validity of the transaction. In fact, this kind of cell would not be possible without the ability to introspect. This collection account cell is ideal as an institutional method of receiving money because it pools funds and has the disadvantage of not having a good sense of privacy.

(4) Lock reads other types (and data)

An interesting application of this capability is stake tokens. Lock will decide whether it can use its own capacity based on the number of tokens in the other inputs, and where it can be spent (requires the ability to introspect lock).

(5) Type reads other locks

Not sure, but it can be assumed useful. For example, you can check in Type that the Locks of the inputs and outputs of a transaction remain unchanged.

(6) Type Scirpt reads other types (and data)

Trading cards? Collect n tokens in exchange for a bigger token :)

VI. Conclusion

Compared to the previous smart contract systems that can be programmed with arbitrary computation, such as Ethereum, Nervos Network takes a different structure; As a result, it is often difficult to understand the Nervos Network based on the knowledge of the smart contract systems of the past. This paper proposes a method to understand the programmability of CKB Cell, starting from the application programming of a structure that is more restricted than CKB Cell, BTC UTXO. And, using the concept of “introspection” to understand the “cross-contract access” capabilities of cells, we can divide the situations in which introspective capabilities are used and determine their specific uses.

Recension:

  1. Regardless of the Cell’s cross-access capabilities (i.e., introspection capabilities), locks can be considered as Bitcoin with state and programming capabilities that have reached the extreme, so that all Bitcoin-based applications can be programmed on this basis alone;
  2. Regardless of the cross-access capability (i.e., introspection ability) of the cell, the distinction between locks and types can be regarded as a security upgrade: it separates the asset definition and custody method of the UDT; In addition, the type s (and data) of the exposable state achieve the effect of UDT is first-class citizen.

The above two points mean something with the same paradigm as “BTC + RGB” but with more programming capabilities;

  1. Considering Cell’s introspective ability, Cell can get stronger programming capabilities than post-covenants BTC UTXO and implement something that is difficult to achieve with BTC + RGB (because BTC can’t read the state of RGB)

There are not many specific examples of these uses, but this is due to the author’s lack of understanding of the ecology of CKB. Over time, it is believed that more and more imagination will be invested in it, and applications that are unimaginable today will be put together.

Acknowledgments

Thanks to Retric, Jan Xie and Xue Jie for their feedback during the writing of the article. Of course, I am responsible for all the mistakes in the text.

References

Accounts, Strict Access Lists, and UTXOs

Restrictions in Bitcoin: Taxonomy for review

Cell Model

Nervos CKB in a Nutshell

Bitcoin’s programmability

On Account Abstraction (2022)

What is a Bitcoin Merkelized Abstract Syntax Tree?

BIP 345: OP_VAULT proposal

Introduction to TLUV restriction opcodes

The components that construct the contract are upgraded with Bitcoin

Eltoo explained

An NFT Secured Lending Contract Based on Committed Transactions · btc-study/OP_QUESTION · Discussion #7

Link to original article

View Original
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
  • Reward
  • Comment
  • Repost
  • Share
Comment
0/400
No comments
Trade Crypto Anywhere Anytime
qrCode
Scan to download Gate App
Community
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)