From Bitcoin application programming, a detailed explanation of CKB's programmability.

The following content is reposted from the Nervos Talk forum, authored by Ajian (editor-in-chief of the Bitcoin content platform BTC Study).

Summary

Understanding the programmability of a system requires us to identify the structural features of the system. Exploring the programmability of applications based on Bitcoin script helps us understand the basic structure of CKB Cells and their programming paradigms. Moreover, it can decompose the programming components of CKB into appropriate parts and help us understand the programmability gains brought by each part.

1. Introduction

“Programmability” is a dimension that people often use when comparing blockchain systems. However, there is often a divergence in the way programmability is described. One common expression is "XX blockchain supports Turing complete programming languages", or "XX blockchain supports general programming", which aims to indicate that the "XX blockchain" has powerful programmability. The implications of these statements are somewhat reasonable: systems that support Turing complete programming are generally easier to program than those that do not. However, the structural characteristics of smart contract systems have multiple aspects, and this statement only involves one aspect, so it is not enough to gain a deep understanding based on it: developers cannot get guidance from it, and ordinary users cannot distinguish scams based on it.

The structural features of the smart contract system include:

  • The basic form of state expression (account vs. transaction output)
  • Whether to allow arbitrary computation (the concept of "Turing completeness" is related to this aspect)
  • Can the execution process create new data or only return a boolean value? (Computation vs. Verification)
  • Allowing extra state to be recorded within the contract
  • Whether a contract can access the state of another contract while it is being executed

So, in addition to "whether programmable computing" outside, at least four other aspects will affect the programmability of a smart contract system. It can even be said that these other aspects are more important because they determine more deeply what is easy to achieve, what is difficult to achieve, what is a more economical implementation, and what is a less efficient implementation.

For example, people often use Ethereum as a good example of programmability, but the basic form of state expression in Ethereum is accounts, which makes it difficult to program point-to-point contracts (such as payment channels, one-on-one betting contracts) - not impossible, just not very efficient. The Ethereum ecosystem has indeed made attempts to implement payment channels/state channels, and there have been many theoretical discussions, but these projects seem to be inactive to date - which obviously cannot be attributed to the lack of effort by developers. Nowadays, the active projects on Ethereum have adopted the form of "funding pools" rather than "point-to-point contracts," and this is not accidental. Similarly, people may be very satisfied with the programmability of Ethereum, but if we want to achieve "account abstraction" (which can also be understood as the generalization of the wallet concept), the account model can be said to have inherent limitations.

Similarly, exploring the programmability of CKB also requires us to understand the structural characteristics of the CKB smart contract system in these aspects. It is already known to us that CKB allows for arbitrary computation, allows for recording additional state within contracts, and also permits one contract to access the state of another contract during execution. However, the form of its contract is the output of a transaction (referred to as a "Cell"), which fundamentally differentiates it from Ethereum. Therefore, an understanding of the Ethereum smart contract system and its contract instances does not help us understand how CKB achieves these structural characteristics, nor does it help us recognize the programmability of CKB.

Fortunately, the smart contracts on Bitcoin seem to provide the best foundation for us to understand the programmability of CKB. This is not only because the basic form of state expression on Bitcoin is also the output of transactions (referred to as "UTXO"), but also because, with the concept of "covenants" proposed by the Bitcoin community, we can understand the reason why CKB has the above structural characteristics, and appropriately decompose the final effect into several parts to identify the programmability gains they bring one by one.

2. CKB vs. BTC: What's Different?

Basic Structure

As a basic form of expressing the state of Bitcoin, Bitcoin's UTXO (Unspent Transaction Output) has two fields:

  • The amount, in satoshis (Satoshi), represents the Bitcoin value of the UTXO;
  • Script public key, also known as locking script, represents the conditions required to spend the funds, which is the smart contract program that sets the conditions for unlocking the funds.

Compared to the later smart contract systems, Bitcoin scripts are quite limited:

  • It does not allow arbitrary computation for programming; there are only a few practical computations that can be verified (signature check, hash pre-image check, time check).
  • It does not allow additional state to be recorded within the contract; (for example, you cannot use a script to limit the proportion/limit of a single spending; nor can you hide a token within it)
  • It also does not allow access to the state of another contract at runtime (each script is an independent universe and does not depend on each other).

This script, although limited, is not lacking in the ability to produce amazing applications through programming. It is also the basis for exploring the programmability of CKB. There will be a dedicated section later to introduce two examples of Bitcoin script programming.

On the contrary, the state unit of CKB is called a "Cell", which has four fields:

  • Capacity, similar to the amount of UTXO, expresses the space size that the Cell can occupy, in bytes (Bytes);
  • Lock, similar to UTXO script public key, defines the ownership of this Cell; only when the provided data can pass through Lock, can this Cell be "updated" (or released this Cell and mint new Cells) using these Capacity.
  • Data, data, any data, its volume is limited by Capacity;
  • Type, optional script, used to set conditions for updating Data.

In addition, Lock and Type can also be programmed for arbitrary calculations. You can program any signature verification algorithm, or any pre-image check of a hash algorithm, and so on and so forth.

Readers can easily see that Cell offers improvements in programmability compared to UTXO.

  • Cell can program arbitrary calculations, rather than being limited to programming only specific types of calculations; its ownership verification will be more flexible;
  • Because of the Data and Type fields, Cell can record additional states; this allows Cell to carry so-called "UDT (User-defined Token)".

Combining the "transaction output" structure of Cell itself, these two points can bring about enormous benefits. However, from the above description alone, we do not yet know how Cell achieves "one contract accessing the state of another contract at runtime." For this, we need to rely on a concept that the Bitcoin community has been discussing for a long time: "covenants".

Restrictions and Introspection

The original intention of the restriction clause is to limit where a sum of money can be spent. In the current Bitcoin (which has not yet deployed any proposed restriction clauses), once funds are unlocked, they can be spent anywhere (payable to any script public key). However, the idea of a restriction clause is that it can be somehow restricted to only be spent in certain places. For example, a certain UTXO can only be spent by a certain transaction. Therefore, even if someone can provide a signature for this UTXO, where it can be spent has already been determined by this transaction. This feature may seem a bit strange, but it can lead to some interesting applications, which will be specifically introduced in a later section. Importantly, it is the key to further understanding the programmability of CKB.

Rusty Russell correctly pointed out that the restrictive clause can be understood as the "introspection" ability of a transaction. That is, when a UTXO A is spent by a transaction B, the script operation program can read part (or all) of transaction B, and then check if they are consistent with the parameters required by the script in advance. For example, whether the script public key of the first output of transaction A is consistent with the script public key required by UTXO A (this is the original meaning of the restrictive clause).

Astute readers will realize that with full introspection capabilities, the input of a transaction can read the state of another input of the same transaction, thus achieving the ability we mentioned earlier, which is "the ability for one contract to access the state of another contract at runtime". In fact, CKB Cell is designed exactly for this purpose.

Based on this, we can further divide this complete introspective ability into four scenarios.

  • Lock Read the Lock of other (inputs and outputs)
  • Lock Read the Type (and Data) of other (inputs and outputs)
  • Type Read the Lock of Others (Input and Output)
  • Read the Type (as well as Data) of other (input and output) Types

This allows us to analyze the introspective capabilities of each part in different application scenarios, that is, to analyze the programmability gains brought to us by each part under certain assumptions (the division of labor between Lock and Type functions).

In the following two sections, we will respectively understand the current (proposed non-limiting terms) Bitcoin script programming, and the expected functionality of the proposed limiting terms, in order to specifically understand how CKB Cell can be programmed and improved.

Three. Bitcoin Script Programming

In this section, "Lighting Network" and "Discreet Log Contract (DLC)" will be used as examples of Bitcoin script-based application programming. Before we delve into it, we need to understand two concepts.

OP_IF and "Promise Trading"

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

In the case of the famous "哈希时间锁合约(HTLC)" contract, this script can be translated into plain language as:

Either Bob can reveal the preimage behind a hash value H and provide his signature to spend this fund;

Either Alice can spend the funds after a period of time T with her own signature.

This "either... or..." effect is achieved through the use of control flow operators.

HTLC's most prominent advantage is that it can bundle multiple operations together and achieve atomicity. For example, Alice wants to exchange CKB with Bob using BTC. In this case, Bob can first provide a hash value and create an HTLC on the Nervos Network. Then Alice creates an HTLC on Bitcoin using the same hash value. Either Bob takes the BTC Alice paid on Bitcoin and reveals the preimage, allowing Alice to withdraw the CKB on the Nervos Network. Or Bob does not reveal the preimage, both contracts expire, and Alice and Bob can retrieve their respective funds.

After the Taproot soft fork is activated, this feature of multiple unlocking paths is further enhanced by the introduction of MAST (Merkle Abstract Syntax Trees): we can turn an unlocking path into a leaf on the Merkle tree, and each leaf is independent, so there is no longer a need to use such flow control opcodes; moreover, because revealing one path does not expose other paths, we can add more unlocking paths to an output without worrying about economic issues.

The second concept is "commitment transaction". The idea of a commitment transaction is that in some cases, a valid Bitcoin transaction is still considered real and binding even if it does not receive blockchain confirmation.

For example, Alice and Bob jointly own a UTXO, which requires their signatures to spend. At this point, Alice constructs a transaction to spend it, transferring 60% of its value to Bob and the remaining value to herself. Alice provides her signature for this transaction and sends it to Bob. For Bob, there is no need to broadcast this transaction to the Bitcoin network or have it confirmed on the blockchain. The payment effect of this transaction is real and trustworthy. This is because Alice cannot spend this UTXO alone (thus preventing double spending), and the signature provided by Alice is valid. Bob can add his own signature at any time and broadcast the transaction to cash out the payment. In other words, Alice provides Bob with a "trustworthy commitment" through this valid (off-chain) transaction.

Promised transactions are a key concept in Bitcoin application programming. As mentioned earlier, Bitcoin contracts are based on verification, stateless, and do not allow cross-access. However, if the contract does not carry the state, where are these states stored and how does the contract safely advance (change the state)? Promised transactions provide a straightforward answer: the state of the contract can be expressed in the form of transactions, so that the participants of the contract can keep the states themselves without having to display them on the blockchain; the issue of state changes in the contract can also be transformed into how to safely update the promised transactions. In addition, if we are concerned about the danger of entering a contract (for example, entering a contract that requires both parties to sign before spending, facing the risk of the other party not responding and getting stuck), then we only need to generate a promised transaction that spends the contract in advance and obtain the signature to mitigate the risk and eliminate trust in other participants.

Lighting Channels and Lighting Network

The Lightning Network is a type of one-to-one contract, in which both parties can pay each other an unlimited number of times without requiring any single payment to be confirmed on the blockchain. As you might expect, it employs commitment transactions.

In explaining the part about "commitment transactions", we have introduced a payment channel that only uses 2-of-2 multisig contracts and can only achieve one-way payments. That is, it is either Alice continuously paying Bob or Bob continuously paying Alice until exhausting their balance in the contract. If it is a bidirectional payment, it means that after a certain state update, one party's balance may become less than before, but they still possess the previous commitment transaction signed by the other party. Is there any way to prevent them from broadcasting the old commitment transaction and only allowing them to broadcast the latest commitment transaction?

The solution to this problem in the Lightning Network is called "LN-Penalty". Now, let's assume Alice and Bob each have 5 BTC in a channel. Now Alice wants to pay Bob 1 BTC, so she signs a commitment transaction like this and sends it to Bob:

Enter #0, 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: Either Alice-Bob joint temporary public key #1 single signature or T1 time lock, Bob single signature.

Bob also signs a commitment transaction (corresponding to the above transaction) and sends it to Alice.

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

Output #0, 6 BTC: Bob single signature

Output #1, 4 BTC: Either Bob-Alice joint temporary public key #1 single signature or T1 timelock, Alice single signature.

The trick here lies in the "joint temporary public key", which is generated using one's own public key and the public key provided by the other party. For example, the joint temporary public key of Alice-Bob is obtained by Alice using her own public key and the one provided by Bob, each multiplied by a hash value and then added together. When this 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 this joint temporary public key. This is the key to "revoke" the old state in the Lightning Network.

When the next channel state update (payment initiation) occurs, both parties exchange the private keys of the temporary public keys handed over to each other in the previous round. In this way, participants no longer dare to broadcast the previous commitment transaction they received: this commitment transaction has two paths for allocating value to their own outputs, and the private key of the temporary public key path has been known by the other party. Therefore, once the old commitment transaction is broadcasted, the other party can immediately use this joint temporary private key to take away all the funds in this output. This is the meaning of "LN-Penalty".

The specific order of interaction is as follows: the party initiating the payment first requests a new temporary public key from the other party, then constructs a new commitment transaction and hands it over to the other party; the party receiving the commitment transaction exposes the private key corresponding to the temporary public key given in the previous round to the other party. This order of interaction ensures that participants always receive new commitment transactions first and then invalidate the commitment transactions they received in the previous round, thus it is trustless.

The key designs of the Lightning Network are as follows:

Both parties always use promise transactions to express the internal state of the contract and represent payments with changes in amounts.

The promise transaction always spends the same input (the input that requires both parties to provide signatures at the same time), so all promise transactions are competing with each other, and only one can eventually get confirmed on the blockchain.

Two signatories do not sign the same committed transaction (although they are paired); instead, they always sign a transaction that is more favorable to themselves. In other words, the committed transactions that participants receive are always unfavorable to themselves.

This disadvantage manifests itself in the fact that the outputs that allocate value to oneself have two unlocking paths: one path can be unlocked by one's own signature, but requires a certain waiting period; while the other path uses the counterparty's public key, and is only protected when one's temporary private key is not exposed.

In each payment, both parties exchange the temporary private keys used in the previous round with a new commitment transaction, so the party that hands over the temporary private key no longer dares to broadcast the old commitment transaction. Therefore, the previous commitment transaction is "revoked" and the contract state is updated. (In fact, these commitment transactions are valid transactions that can be broadcast on the blockchain, but participants do not dare to broadcast them due to punishment)

Either party can withdraw from the contract by trading the signed commitment of the other party at any time; however, if both parties are willing to cooperate, they can sign a new transaction that allows both parties to immediately retrieve their own money.

Finally, because conditional transactions can also be included in HTLC, the Lightning Network can also forward payments. Assuming Alice can find a path composed of consecutive Lightning channels to reach Daniel, it is possible to achieve trustless multi-hop payments without opening a channel with Daniel. This is the Lightning Network.

Alice -- HTLC --\u003e Bob -- HTLC --\u003e Carol -- HTLC --\u003e Daniel

Alice <-- Pre-image -- Bob <-- Pre-image -- Carol <-- Pre-image -- Daniel

When Alice finds such a path and wants to pay Daniel, she requests a hash value from Daniel to construct an HTLC for Bob and prompts Bob to forward a message to Carol and provide the same HTLC. The message also prompts Carol to forward the message to Daniel and provide the same HTLC. When the message reaches Daniel, he reveals the preimage to Carol, thereby obtaining the value of the HTLC and updating the contract state. Carol does the same and obtains payment from Bob and updates the channel state. Finally, Bob reveals the preimage to Alice and updates the state. Due to the nature of HTLC, this series of payments either succeeds together or fails together, making it trustless.

Lightning Network is composed of one channel after another, and each channel (contract) is independent of each other. This means that Alice only needs to know what happens in her own channel with Bob, and does not need to pay attention to how many interactions have occurred in other people's channels, or which currency these interactions use, or even whether they are really using the channel.

The scalability of the Lighting Network is not only reflected in the payment speed within a lightning channel, which is only limited by the hardware resources invested by both parties, but also in the fact that, due to the decentralized storage of state, individual nodes can leverage the maximum leverage with the lowest cost.

Caution Log Contract

Prudent Log Contract (DLC) uses a cryptographic technique called "adaptor signature" to enable Bitcoin scripts to programmatically create financial contracts that depend on external events.

Adapter signatures make a signature valid only after adding a private key. Taking Schnorr signature as an example, the standard form of Schnorr signature is (R, s), where:

R = r.G # The nonce value r used for signature multiplication with the elliptic curve generating point, also known as the public key of r

s = r + Hash(R || m || P) \* p # p is the private key of the signature, and P is the public key.

To verify the signature, verify that s.G = r.G + Hash(R || m || P) * p.G = R + Hash(R || m || P) * PK.

Assuming I provide a pair of data (R, s'), where:

R = R1 + R2 = r1.G + r2.G

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

Obviously, this is not a valid Schnorr signature and it cannot pass the verification formula. However, I can prove to the validators that by only knowing the private key r2 of R2, it can be turned into a valid signature.

s'.G + R2 = R1 + Hash(R || m || P) * P + R2 = R + Hash(R || m || P) * P

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

Assuming that Alice and Bob want to bet on the outcome of a basketball game. Alice and Bob bet on the victory of the Green Devils and the Arlinas, with a stake of 1 BTC. In addition, the sports website Carol promises to publish a signature s_ci on the result using a nonce R_c when the outcome of the game is revealed.

It can be seen that there are three possible outcomes (hence Carol's signature has three possibilities):

  • Green Demon wins, Alice wins 1 BTC
  • Arinna wins and Bob wins 1 BTC
  • Draw, both players' funds will be returned in the original way.

For this, the two parties create a commitment transaction for each possible outcome. For example, the commitment transaction they created for the first outcome is as follows:

Enter #0, 2 BTC: Alie-Bob 2-of-2 Multisig Output (i.e. Betting Contract)

Output #0, 2 BTC: Alice single signature

But the signatures created by Alice and Bob for this transaction are not (R, s), but adapter signatures (R, s'); that is, the signatures given to each other cannot be directly used to unlock this contract, and a secret value must be revealed. This secret value is the pre-image of s_c_1.G, that is, Carol's signature! Because 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 magic wins' || PK_c) * PK_c).

When the results are announced, assuming the Green Team wins, Carol will publish the signature (R_c, s_c_1). Then, both Alice and Bob can complete the opponent's adapter signature, add their own signature, and make the above transaction an effective one, broadcasting it to the network to trigger the settlement effect. But if the Green Team does not win, Carol will not publish s_c_1, and this commitment transaction will not be able to become an effective transaction.

By analogy, the same applies to the other two transactions. In this way, Alice and Bob make the execution of this contract depend on external events (specifically, the broadcast of external events by the oracle in the form of a signature), without the need to trust the counterparty. Various financial contracts, such as futures and options, can be implemented in this way.

Compared with other forms of implementation, the most significant feature of the Prudent Log Contract is its privacy: (1) Alice and Bob do not need to inform Carol that they are using Carol's data, which has no impact on the execution of the contract; (2) On-chain observers, including Carol, cannot determine which website's services Alice and Bob are using, or even whether their contract is a gambling contract (rather than a lightning channel).

IV. Introduction to the Application of Restriction Clauses

OP_CTV and Congestion Control

The developers of the Bitcoin community have proposed several proposals that can be classified as restrictive terms. Currently, the most famous proposal is OP_CHECKTEMPLATEVERIFY (OP_CTV), which has a relatively simple concept but retains considerable flexibility, making it popular in the Bitcoin community that advocates simplicity. The idea of OP_CTV is to promise a hash value in the script to constrain the funds to be spent only by the transaction represented by this hash value; this hash value promises the output and most of the fields of the transaction, but does not promise the input of the transaction, only the quantity of the input.

"Congestion control" is a good example that demonstrates the features of OP_CTV. Its basic application scenario is to help a large number of users withdraw from an exchange (a trusted environment) to a fund pool; because this fund pool plans future spending using OP_CTV, it can ensure that users can withdraw from the fund pool without trust, without the need for anyone's help; and because this fund pool only appears as a UTXO, it avoids paying a large amount of transaction fees when the demand for on-chain transactions is high (from n outputs reduced to 1 output; also reduced from n transactions to 1 transaction). Users in the pool can also seize the opportunity to withdraw from the pool again.

Let's say Alice, Bob, Carol want to withdraw 5 BTC, 3 BTC, and 2 BTC from the exchanges, respectively. Then exchange can make a 10 BTC output with 3 OP_CTV branches. Suppose Alice wants to withdraw money, she can use branch 1, and the transaction represented by the hash value used by the OP_CTV of that 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 take out only 3 BTC and send the remaining 2 BTC to Carol.

Bob or Carol wants to withdraw money, the same applies. When they withdraw, they can only use transactions that pass the corresponding OP_CTV check, that is, they can only pay themselves the corresponding amount and cannot withdraw funds at will; the remaining funds will be returned to a fund pool locked by OP_CTV, ensuring that regardless of the withdrawal order of users, the remaining users can withdraw from the pool without trust.

In abstract, the role of OP_CTV here is to plan the path for the contract to reach its end, so that regardless of which path the contract takes or what state it reaches, the funds in the contract pool can maintain the attribute of trustless exit.

This OP_CTV has another interesting use case: "invisible one-way payment channels". Assuming Alice forms such a fund pool and ensures that funds can be withdrawn trustlessly to an output with the following script:

Either Alice and Bob spend it together or, after a while, Alice can spend it alone.

If Alice does not disclose to Bob, Bob will not know that such an output exists; once Alice discloses to Bob, Bob can treat this output as a time-limited one-way payment channel. Alice can immediately use the funds in it to pay Bob without waiting for blockchain confirmation. Bob only needs to let Alice's promised transaction be recorded on the chain before Alice can spend it alone.

OP_Vault and Safe

OP_VAULT is a proposal for a set of restrictive clauses specifically designed for constructing "vault contracts".

The vault contract aims to be a more secure and advanced form of autonomous custody. While current multi-signature contracts can eliminate single-point failures of individual private keys, if an attacker truly obtains the threshold number of private keys, the wallet owner is helpless. The vault hopes to impose a limit on the amount of funds spent in a single transaction; at the same time, when withdrawing through the regular path, the withdrawal operation will enforce a waiting period; and during the waiting period, the withdrawal operation can be interrupted by the emergency recovery wallet operation. With such a contract, even if it is breached, the wallet owner can initiate countermeasures (using the emergency recovery branch).

In theory, OP_CTV can also program such contracts, but there are many inconveniences, one of which is the transaction fee: while committing to the transaction, it also commits to the fee the transaction will pay. Given the purpose of such contracts, the time interval for setting up and withdrawing the contract must be very long, making it almost impossible to predict the appropriate fee. Although OP_CTV has no input restrictions and can increase the fee by increasing the input, the provided input will all become the fee, making it impractical. Another method is CPFP, which means providing a fee in a new transaction by spending the withdrawn funds. In addition, using OP_CTV also means that such vault contracts cannot be batch withdrawn (of course, they cannot be batch restored either).

OP_VAULT's proposal attempts to solve these problems by proposing new opcodes (OP_VAULT and OP_UNVAULT). OP_UNVAULT is designed specifically for batch recovery and will not be discussed temporarily. The action of OP_VAULT is as follows: when we place it on a branch of the script tree, it can be used to commit to an opcode (such as OP_CTV) that can be used without specifying specific parameters; when spending this branch, the transaction can pass in specific parameters, but cannot change other branches. Therefore, it does not need to pre-set the fee and can set the fee when spending this branch; assuming this branch also has a time lock, it will enforce a time lock; finally, because it can only change the branch it is on, other branches on the new script tree (including emergency recovery branches) will not be changed, allowing us to interrupt such withdrawal operations.

In addition, there are two points worth mentioning: (1) The action of the OP_VAULT opcode is similar to another proposed restriction clause: OP_TLUV; Jeremy Rubin correctly pointed out that this has to some extent already introduced the concept of "computation": OP_TLUV/OP_VAULT first commits to an opcode, allowing users to pass parameters for that opcode through a new transaction, thereby updating the entire script tree leaf; this is no longer "verifying incoming data according to certain conditions," but "generating new meaningful data based on incoming data," although the computation it can enable is relatively limited.

The complete OP_VAULT proposal also utilizes some proposals on mempool policy (such as transactions in v3 format) to achieve better results. This reminds us that the meaning of "programming" can be broader than we imagine. (A similar example is Open Transaction in the Nervos Network.)

5. Understanding CKB

In the above two chapters, we introduced how to program interesting applications using scripts on a more restricted structure (Bitcoin UTXO), and also proposed attempts to add introspection capabilities to this structure.

UTXO, although capable of programming these applications, readers can easily notice their shortcomings or areas for optimization, for example:

  • In LN-Penalty, participants in the channel must keep track of every past commitment transaction and the corresponding penalty secret value to protect against fraud by their counterparties, which imposes a storage burden. If there is a mechanism that ensures only the latest commitment transaction is enforced and old commitment transactions are not enforced, this burden can be eliminated. Additionally, it can prevent nodes from mistakenly broadcasting older commitment transactions due to failures, thus avoiding accidental penalties.
  • In DLC, assuming there are many possible outcomes for an event, there are also many signatures that need to be generated and exchanged between the parties in advance, which is a huge burden. In addition, the profits of the DLC contract are directly tied 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 already come up with answers to these issues, which are basically related to a Sighash proposal (BIP-118 AnyPrevOut).

However, if we are programming on CKB, BIP-118 would be available now (the ability to simulate this Sighash tag with introspection and targeted validation of signatures).

By learning Bitcoin programming, we not only understand how to program under the format of "transaction output" (what CKB can program), but also know the improvement methods of these applications (how to use CKB's capabilities to improve them if we program these applications on CKB). For CKB developers, it's almost like using Bitcoin script-based programming as a learning material, or even a shortcut.

Next, we will analyze the programmability of each module in CKB programming one by one. Let's not consider introspection ability for now.

Programmable Lock for Arbitrary Computation

As mentioned above, UTXO cannot be programmatically computed. While DLC can, this means that it can programmatically deploy everything based on UTXO, including but not limited to the Lightning Network and DLC as mentioned above.

In addition, this verifiable arbitrary computation capability also allows Lock to use more identity verification methods than UTXO, and is more flexible. For example, we can implement a lightning channel on CKB where one party uses ECDSA signature and the other party uses RSA signature.

In fact, this is one of the areas that people have been exploring on CKB: using this flexible identity verification capability for user self-custody, thus achieving the so-called "account abstraction" - the authorization and control of transaction validity can be restored in a very flexible manner, with almost no restrictions. In principle, this is a combination of "multi-spending branches" and "arbitrary identity verification methods". Examples of implementation include JoyID Wallet and UniPass.

In addition, Lock can also implement the eltoo proposal, thus achieving the lightning network channel that only needs to retain the latest committed transaction (in fact, eltoo can simplify all peer-to-peer contracts).

Programmable Arbitrary Computation Type

As mentioned above, one major use case of Type is to program UDT. Combined with Lock, this means we can implement lightning channels with UDT as the underlying asset (as well as other types of contracts).

In fact, the separation of Lock and Type can be seen as a security upgrade: Lock focuses on implementing custody methods or contract-based protocols, while Type focuses on the definition of UDT.

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

For example: I once proposed a protocol for trust-free NFT collateralized lending on Bitcoin. The key to this protocol is a commitment transaction, the input value of which is less than the output value (so it is not yet a valid transaction), but once sufficient input is provided for this transaction, it becomes valid: once the borrower can repay the loan, the lender cannot take possession of the staked NFT. However, the trust-free nature of this commitment transaction is based on checking the amounts of inputs and outputs, so the borrower can only repay in Bitcoin - even if both the borrower and the lender are willing to accept another currency (such as USDT issued through the RGB protocol), the commitment transaction in Bitcoin cannot guarantee that the lender will get back their NFT as long as the borrower repays enough USDT, because the Bitcoin transaction is completely unaware of the status of USDT! (Revised: In other words, it is impossible to construct a commitment transaction conditional on repaying with USDT.)

If we can initiate an inspection based on the definition of UDT, it will allow the lender to sign another commitment transaction, allowing the borrower to repay the loan using USDT. The transaction will check the input and output quantities of USDT, thus giving the user the non-trustworthiness of using USDT for repayment.

Revisions: Assuming that the NFT used as collateral and the token used for repayment are issued using the same protocol (such as RGB), the problem here can be solved. We can construct a committed transaction based on the RGB protocol, so that the state transition of the NFT and the repayment can occur synchronously (binding two state transitions with transactions in the RGB protocol). However, because the RGB transaction also relies on Bitcoin transactions, there will be some difficulties in constructing the committed transaction here. In summary, although the problem can be solved, it is not possible to make the token a first-class citizen.

Next, let's consider introspection ability.

Read other Locks.

This means that after the proposed implementation of the restriction clause, all programming possibilities on Bitcoin UTXO will be limited. This includes the mentioned vault contract and applications based on OP_CTV (such as congestion control).

XueJie once mentioned a very interesting example: you can implement a payment account Cell on CKB. When using this Cell as the input for a transaction, if the output Cell (using the same Lock) has more Capacity, this input does not need to provide a signature and will not affect the validity of the transaction. In fact, without introspection capabilities, this type of Cell cannot be implemented. This payment account Cell is very suitable as a collection method for institutions, as it can aggregate funds. The drawback is that its privacy is not good.

Read other Type s (as well as Data) for Lock

One interesting application of this capability is equity Token. Lock will determine whether it can use its own Capacity, as well as where these Capacity can be spent (requires the ability to introspect Lock), based on the number of Tokens in other inputs.

Type Read Other Lock S

Uncertain, but it can be assumed as useful. For example, the Locks of the inputs and outputs of a transaction can be checked to remain unchanged in Type.

Read Other Type s (and Data) in Type Scirpt

Card exchange? Collecting n tokens can be exchanged for a bigger token : )

Conclusion

In comparison with the programmable smart contract systems previously presented (such as Ethereum), Nervos Network adopts a different structure; therefore, understanding those previous smart contract systems often proves insufficient for comprehending the basis of Nervos Network. This article starts from the application programming of a structure more restricted than CKB Cell - BTC UTXO - and proposes a method to understand the programmability of CKB Cell. Furthermore, by utilizing the concept of "introspection" to comprehend the "cross-contract access" capability of Cell, we can categorize the scenarios using introspection capabilities and determine their specific uses.

Revised:

  1. Without considering the cross-access ability of Cell (i.e., introspection ability), lock s can be regarded as a stateful and programmable Bitcoin, so based on this alone, it can be used to program all applications based on Bitcoin.

  2. Without considering the cross-accessibility (i.e., introspection capability) of Cells, the differentiation between locked s and type s can be regarded as a security upgrade: it separates the asset definition and custody method of UDT; in addition, the exposed state of type s (as well as Data) achieves the effect of UDT being a first-class citizen.

The above two points mean something with a stronger programming ability but the same paradigm as "BTC + RGB";

  1. Considering the introspective ability of Cell, Cell can gain stronger programming capabilities than post-covenants BTC UTXO, and achieve some things that are difficult to achieve with BTC + RGB (because BTC cannot read the state of RGB).

Regarding these use cases, this article cannot provide many specific examples, but this is because the author lacks understanding of the CKB ecosystem. In time, it is believed that people will invest more and more imagination in it, combining applications that are currently hard to imagine.

Thanks

Thank you Retric, Jan Xie, and Xue Jie for the feedback provided during the writing process. Of course, I take full responsibility for any errors in the article.

References:

5._07_05_introduction_to_ckb__programming_validation_model/

  1. (II) Prudent Log Contract (DLC)

13.\_QUESTION/discussions/7

View Original
  • Reward
  • Comment
  • Share
Comment
No comments