Nervos is a layered, multi-asset store of value public chain, an original design that is completely different from other public chains. Layer 1 focuses on security and system robustness, leaving usage, performance, and so on to Layer 2. A clear division of labor also creates many different experiences and trade-offs during development. In this article, Nervos CKB core developer JJy takes a look at how an important underlying feature of Nervos — off-chain determinism — makes the system more secure and reduces resource consumption, and what trade-offs are involved.
How do I get the current block height
I’ve heard developers complain over and over again about why they can’t read the current block height in their scripts (smart contracts).
As every developer knows, reading the current block height from smart contracts is a basic function on Ethereum and other blockchains that use EVM. So if CKB is the next generation of blockchain, as we say, then why can’t it do what the last generation of public chains did?
Well, I guess no one can answer that question, and the CKB core team doesn’t often explain the unique design of CKB, which I think the core team could do a better job of.
So I decided to write this article to explain the tradeoff of this design: why can’t we read the current block height in the smart contract (script).
The right way
Let’s start by verifying the correct way for CKB scripts to read block heights!
My observation is that most developers calculate the block time between two actions by requesting block height. In abstract terms, a user makes a deposit at block height X and withdraws at block height Y. After the withdrawal occurs, the smart contract needs to count blocks from X to Y, and send rewards based on how long the user has deposited the money (note: liquidity mining, for example) or do something similar.
Ethereum can directly read block heights and calculate rewards. However, in CKB, we have to do something other than read the block height directly:
- Transaction Valid Since can be used to limit withdrawal transactions to ensure that a withdrawal transaction does not occur until at least Z blocks after the deposit has been completed. However, this allows the user to extend the withdrawal time beyond block Z, which may not be appropriate in some cases.
2. We can take a two-step withdrawal to locate the block height. The first step is to read the block height X of the user’s deposit by CKB Syscalls and record the height X in the new “Ready to withdraw Cell”. The second step is that we can use syscall to read cell Y for withdrawal and X from the data field of this cell.
So we can also calculate the block time to be Y minus X. (Think Nervos DAO design.)
Subchain determinism
So what is the purpose of this? Developers obviously prefer a simpler, more intuitive approach, so why would CKB use such a difficult approach to do a simple job? !
And that’s all because of subchain determinism. Let’s start with two questions: What are the inputs to ethereum contracts? What is the input to the CKB script?
If we treat the contract (or script) as a function “F”, then we can express the calculation of the smart contract in the following form:
On Ethereum:
output = f(tx, state tree, current blockchain)
Copy the code
On the CKB:
output = f(tx, deterministic blockchain)
Copy the code
In Ethereum, a contract can retrieve information from three inputs: TX, account state tree, and current blockchain state.
For example, smart contracts can read the current block height and block hash from the blockchain.
In CKB, we only allow scripts to read deterministic input. If a user wants to read information from the blockchain, then the user must first include a block hash in the transaction. Therefore, all the information that a script can read is deterministic. We call this sub-chain determinism, which is a fundamental feature of CKB.
advantages
There are some benefits to off-chain determinism, the most important of which is that once we verify a transaction, we know it will be valid or invalid, because the inputs and outputs are deterministic and the verification result is independent of the blockchain state.
This certainty introduces a validation policy in CKB where we only validate transactions once before pushing them into the memory pool. When we package a transaction into a block, we only need to check whether the transaction input is still unused, which is a small cost compared to the full validation of the transaction.
This off-chain certainty of transactions is not bound to just one node; We can guarantee that a transaction is valid, even if we send it over a P2P network. Because if a transaction is valid, it will be valid forever, CKB broadcasts only valid transactions to other nodes. If a malicious node tries to broadcast an invalid transaction, other nodes in the network will immediately disable it once the transaction sent by the malicious node cannot be verified. Since invalid transactions cannot be broadcast to the CKB network, CKB only packages valid transactions into blocks, which I think is a major advantage of CKB.
Note that this is not possible in Ethereum because transactions with Ethereum are not deterministic below the chain and a transaction can fail at block height 42 even if it is valid at block height 41. As a result, we never know whether the failed transaction was intentionally sent by a malicious node or failed because of a change in the current state of the blockchain.
So Ethereum chose another approach, which allowed nodes to broadcast invalid messages and package them into blocks. The agreement then allows miners to penalize failed transactions by charging the sender’s account the maximum fee. The mechanism is designed to encourage users to send only valid text messages to enhance security; But even if you are an honest user, you can send a failed transaction by accidentally running into an invalid contract state. (When I tried to deposit my money with Curve, I lost about $50 on a failed trade.)
The two different design ideas of including only valid transactions in the block, or including failed transactions in the block and penalizing the sender, come from different answers to a simple question: Should we allow scripts (smart contracts) to read the current block?
Layer 1 robustness vs user experience
From what I understand, between Layer 1 robustness and user experience, CKB’s design clearly chooses Layer 1 for robustness.
I believe this is the right choice; The only important thing about Layer 1 blockchain is providing robust and secure services. This trade-off does not mean that CKB does not care about the user experience. Remember CKB’s slogan – Build Layer 1 for Layer 2. In this case, Layer 1 is for robustness and Layer 2 (above) is for user experience.
In a layered architecture, most people use the technology at the top, and only a few people need to access it directly from the bottom. For example, most users on the Internet use HTTP or WebSocket; Few people use TCP or UDP, and almost no one uses IP directly. The layering diagram of the Internet is a useful reference for those unfamiliar with the layered architecture of the Internet.
Source: khan Academy www.khanacademy.org/computing/c…
From a smart contract developer’s point of view, you might find this design difficult to understand, but if you look at the layered architecture, you’ll see that Nervos’s design fits the Layer 1 blockchain perfectly.
Once Nervos’s Layer 2 facility is enabled, developers will be able to easily access the functionality provided by Layer 2, not only to read block heights with Layer 2 (which is easy), but also to use other Layer 2 features that are more powerful (which is left to the developer’s imagination).
Original link:Talk.nervos.org/t/off-chain…By JJY, core developer at CKB
// If you like Nervos and like development
// You can follow me in the comments section
if (you like Nervos && you like dev) {
println("you can leave a message in the comments area and follow me~");
}
Copy the code