CITA-Cloud
目前是在协议中直接把交易和区块等数据结构固定下来的。
message BlockHeader {
// hash of previous BlockHeader
bytes prevhash = 1;
uint64 timestamp = 2;
uint64 height = 3;
bytes transactions_root = 4;
bytes proposer = 5;
}
message Transaction {
uint32 version = 1;
// 1. length is 20 bytes for evm.
// 2. if executor is multi-vm, it will be a path.
bytes to = 2;
// length is less than 128
string nonce = 3;
uint64 quota = 4;
uint64 valid_until_block = 5;
bytes data = 6;
// length is 32 bytes.
bytes value = 7;
// length is 32 bytes.
bytes chain_id = 8;
}
但是最近的思考发现,其中的很多字段都是为了实现某种应用层面的协议而存在的。而且实现方式也有多种,可以根据不同情况进行选择。
比如,BlockHeader
中的timestamp
,就是为了实现一个分布式的时间同步协议,多个节点商议出一个全局的时间。这不仅仅是一个共识的问题,还有跟时间相关的一些特定检查。比如,当前块的时间戳必须大于上一个块,但是又不能大太多,否则很快这个时间就脱离现实时间了。
如果合约和上层应用中不需要跟现实时间这么紧密的时间戳,只需要一个粗略的逻辑时间,那么使用height
就够了,就不需要timestamp
字段了。
prevhash
字段表达了区块间连接的拓扑结构。就像区块链设计模式系列(二)本地优先里提到的,如果是传统的链式结构,那么这个字段就只是一个hash
;如果是DAG
结构,那么就是一组hash
。
transactions_root
字段用于轻节点协议,表达了块中的交易和块头是如何关联的。如果这里采用了默克尔树的组织方式,那么就可以用默克尔路径证明来判断一个交易是否在区块中。如果不需要轻节点,也可以简单的实现成交易数组的hash
。
交易中的字段可以参见 https://docs.citahub.com/zh-CN/cita/rpc-guide/rpc#关于签名交易
比如交易中的 nonce
字段就是为了实现应用层面的去重协议。这里也有多种实现方式可以选择,比如以太坊就选择了自增的序号,而CITA
为了解决前一种方案不能并发发送交易的缺陷,改用随机nonce
。
因此,我们希望可以让用户来自己定义这些协议的组合以及实现方式,这样可以定制出更加贴近实际业务场景的区块链。
具体方式就是让用户来自定义核心的交易和区块等数据结构,并通过protobuf
扩展增加一些标注,方便自动生成相关的代码。
技术方面的信息可以参见 https://rink1969.github.io/protobuf-ext
Demo
工程:https://github.com/rink1969/proto_desc_printer