This is my study notes about CKB programming model, I tried to introduce some advantages about programming on CKB, but I think this article is more like “something about CKB that interests me”. I want to know why you are interested in Nervos CKB, please feel free to comment, it will be very helpful, thank you!
Nervos CKB as Layer 1, is a state-centric architecture in which transactions represent state changes and migrations. CKB provides a unique stateful Turing-complete programming model based on CKB VM and cell model. In this document,I will introduce the CKB Programming model’s some features.
The CKB programming model
If you want to develop based on CKB, it’s recommended that you first understand the programming model. State in CKB is a first-class citizen, states are included in transactions and blocks, and they are synchronized directly between nodes. The CKB programming model consists of three parts:
- state generation (off-chain)
- state storage (Cell model)
- state verification (CKB VM)
In this model, decentralized application logic is split into two parts (generation and verification), which run in different places. State generation logic runs off-chain on the client side, new states are packaged into transactions and broadcasted to the entire network; while state verification takes place on-chain, ensuring the validity of state transitions and creating a trustless system.
Inputs to CKB transactions include references to previous outputs, along with proofs to unlock them. The client includes generated new states as transaction outputs, which are called cells in CKB. Thus the name cell and transaction output are interchangeable. Cells are the primary state storage units in CKB and are assets owned by users that must follow associated application logic specified by scripts.
CKB VM executes these scripts and verifies proofs included in transaction inputs to make sure the user is permitted to use the referenced cells and the state transition is valid under the specified application logic. In this way, all nodes in the network verify that new states are valid and keep these states in custody.
1.Cell model: A generalized version of the UTXO model
The fundamental building block of a Bitcoin transaction is an unspent transaction output or UTXO. UTXO are indivisible chunks of bitcoin currency locked to a specific owner, recorded on the blockchain, and recognized as currency units by the entire network. The data structure is very simple, it only contains two fields:
class TxOut
{
public:
Amount Value;
Script scriptPubKey;
…
}
Every TxOut
represents a coin with its own denomination (Yay bit-”Coin”), which is defined by Value
. The scriptPubKey
is a script which indicates the owner of the coin (and usually refers to the public key of the owner). Only the person who provides the right input that makes the script run successfully can “transfer” the coin to another person.
Cell
The focus of Layer 1 is on state, so the design of CKB as Layer 1 should also lay emphasis on state. A state verified and held by CKB is not simply a number ( Value
) as in Bitcoin, but any data that is considered as valuable and recognized by all the actors. The UTXO model of Bitcoin is obviously unable to make this happen. By modifying value to Value
a space that can store not just an integer, but also any other data, we have a more generalized “ Value
”, or Cell :
pub struct CellOutput {
pub capacity: Capacity,
pub data: Vec,
pub lock: Script,
pub type_: Option,
}
In a Cell, the Value
field is replaced by capacity
and data
fields. These are combined to represent a storage space. capacity
is not only just the amount of the stored tokens, but it is also a limit on how many data the cell can store. That’s where the name comes from, It is the storage capacity of the cell, while data
is where a state described in any given line of bytes is saved.
The Cell model also introduces the concept of lock script
and type script
which is a brand new verification model, we will see that later.
Overall, The UTXO model makes the ledger history more clear, but its lack of generic state storage makes its already inexpressive scripts harder to use, but the Cell model is a generalized version of the UTXO model. It is a very flexible and creative development experience on CKB.
If you want to learn more about Cell Model, please refer to Cell Model.
2.Lock Script & Type Script: A brand new verification model
CKB is dedicated to a brand new verification model and unlike some other blockchains, CKB provides the freedom to develop CKB scripts back to the whole community.
- Lock Script
Every cell has a lock script. The lock script must run when the cell is used as an input in a transaction. A transaction is valid only when all the lock scripts in the inputs exit normally (without exceptions). Since this script runs on inputs, it acts as the lock to control who can unlock and destroy the cell, as well as spend the capacity stored in the cell.
The following is an example lock script code which always exits normally. Anyone can destroy the cell if it uses this code as the lock script.
int main(int argc, char *argv) {
return 0;
}
The most popular way to lock a digital asset is the digital signature created by asymmetric cryptography.
The signature algorithm has two requirements:
- The cell must contain the information for the public key, so only the real private key can create a valid signature.
- The transaction must contain the signatures, which usually signs the whole transaction as the message.
2. Type Script
Type script is very similar to lock script, with two differences:
- Type script is optional.
- In a transaction, CKB must run the type scripts in both inputs and outputs.
Although we can only keep only one type of script in the cell, we don’t want to mess the different responsibilities in a single script. The lock script is only executed for inputs, so its primary responsibility is protecting the cells. Only the owner is allowed to use the cell as input and spend any assets stored in it.
The type script is intended to establish some contracts on the cells. When you get a cell with a specified type, you can ensure that the cell has passed the verification in the specific code. This code is also executed when the cell is destroyed. A typical scenario of type script is to implement a user-defined token. The type script must run on outputs, so the token issuance must be authorized. overall a type script is used to validate certain rules in the cell transformation phase.
If you want to learn more about CKB’s verification model , please refer to Introduction to CKB Script Programming 1: Validation Model.
3.CKB VM:A real mini computer
CKB VM is a RISC-V instruction set based VM for executing type and lock scripts. But what does that even mean? 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.
We can write CKB script codes in JavaScript. 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, duktape, 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.
And we can actually expand from this path, we can have JavaScript on CKB via duktape, we can also have Ruby on CKB via mruby, 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.
If you want to learn more about CKB VM , please refer to RFC:CKB-VM
4.UDT:First-class asset
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.To distinguish from ERC20, we call the tokens issued in CKB user defined token
, or UDT for short.
What is first-class asset?
The concept of first-class asset is actually derived from the first-class function. A first-class Asset is an encrypted Asset that is directly owned by the user and can be manipulated directly.
Why UDT is first-class asset?
While Ethereum has a unique storage space for each contract account, CKB spreads data among multiple cells. A cell’s lock & type script then tells which account the cell belongs to, as well as how you can interact with the cell. In CKB we have a new design to store the balances of UDT users:
- A special type script denotes that the cell stores UDTs.
- The first 4 bytes of the cell data contains the amount of UDTs in current cell.
This design has several implications:
- The storage cost for a UDT cell is always constant, it is irrelevant to the amount of UDTs stored in the cell.
- A user can transfer either all or part of the UDTs in a cell to others
- In practice, there might be numerous cells containing the same UDTs.
- The lock script used to guard a UDT is decoupled from the UDT itself.
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 unlike ERC20 which stores all token users’ balances in the ERC20 contract’s storage space and as we know ERC20 contracts have security vulnerability.
The economic model of CKB focuses on the incentives of state storage. Users are required to pay for state storage of their assets on the blockchain and bear cost proportional to the amount of data stored and length of storage time. This resolves an issue we see when implementing ‘storage rent’ in Ethereum ERC20 contracts for example- when all asset states for all users are mixed, it is difficult to provide each user the ability to pay for storage of only their assets on the blockchain.
If you want to learn more about first-class asset, please refer to First-class Asset.
5.Type ID:Provide the balance between Upgradability vs. Determinism
In the blockchain space, there’s a pair of issues that everyone has to pick sides:
The conflicts between Upgradability and Determinism
Upgradability: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?
Determinism:This one has 2 parts:
- 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?
- Determinism B: if I sign a transaction now, and send it later, will my transaction still be accepted by the blockchain?
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.
If we think about it, we could find that there’re always conflicts between upgradability and determinism:
- 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.
- If a smart contract could be upgraded, an already signed transaction might run into different behaviors, resulting it be rejected by the blockchain.
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,so we have implemented a unique script, named a type ID script . This feature is totally optional in CKB, you can perfectly practice “code is law” principle in CKB like in other blockchains and you can balance the upgradability and determinism. We are just hoping this unique feature will provide new possibilities for people who really need it.
If you want to learn more about Type ID please refer to Introduction to CKB Script Programming 6: Type ID.
6.Advanced Duktape:write CKB script codes in JavaScript
We can have JavaScript on CKB via duktape because of the powerful CKB VM. We can not only have some single pieces of code with very simple logics, but we can parse CKB data structures, put external libraries in the script and so on.Our CKB core developer Xuejie has written an article about how to implement:Introduction to CKB Script Programming 7: Advanced Duktape Examples
The article displays how to create a duktape-powered CKB script with the following requirements:
- External library dependency
- Serialization/Deserialization of CKB data structures
- Hashing
It’s very useful examples for people who want to develop JS projects and you can have a streamlined CKB script development experience via JavaScript & duktape.
7.Debug:Support GDB & REPL based Development/Debugging
Debugging a CKB script is not so different from debugging your everyday program.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.
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. CKB also has support for this type of development/debugging workflow.
If you want to learn more how to debug CKB scripts, please refer to Introduction to CKB Script Programming 5: Debugging.
8.Embrace the WebAssembly ecosystem
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.
Running WebAssembly programs in CKB VM actually has more benefits running this way than directly using a WebAssembly VM:
- 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
imports
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 hard fork when a WebAssembly virtual machine gets updated, if it’s updated. - It’s easy to implement
- 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.
- 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?
We try 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.
Besides, we have a new project that could be used to generate performant WASM program s, you can see how it works in Introduction to CKB Script Programming 8: Performant WASM.
Developer community
We have launched the Nervos Grants Program to empower innovation and development and support the growth of a diverse and thriving ecosystem.
The goal of the program is to attract talent to research and build the necessary tooling for developing solutions around Nervos, and to incentivize developers and projects who are willing and passionate about working on these solutions.
Our long term vision is to be fully decentralized and community-led. Achieving this means bootstrapping individuals, projects and teams who want to make significant contributions toward building out our infrastructure.
- Visit Nervos Talk for a list of the types of submissions we’re hoping to see. If you have the interest, experience and skills to deliver on any project within the scope of the grant categories currently open, we invite you to submit a proposal for funding and join us in building out the Nervos Ecosystem and Common Knowledge Base (CKB).
- As with everything we do, the process and program will be fully transparent. From evaluating applications to voting for the strongest submissions, every step of the program will be open for the community members to review and provide feedback.
Ref: