3. 数据结构
长安链(ChainMaker)核心数据结构皆采用protobuf3语法进行定义,以方便在不同的语言之间进行通信。长安链数据结构模型定义在pb项目下,并按功能和使用范围,分为:
accesscontrol
与访问控制相关的用户账户、组织角色等对象api
与客户端SDK相关的对象common
核心区块头、交易、结果对象config
区块节点配置和网络配置等相关对象consensus
与共识相关的对象,不同的共识算法会有不同的共识对象discovery
用于P2P网络发现的对象net
用于P2P网络广播的消息对象store
进行账本和状态数据存储使用的对象sync
同步数据使用的相关对象txpool
交易池相关对象
ChainMaker官方提供ChainMaker协议的Golang实现,根据protobuf3数据模型定义,生成Golang代码在同级的pb-go目录下。
3.1. 核心数据模型
3.1.1. 区块
3.1.1.1. 结构示意图
![](../images/DataStructure-BlockStructure.png)
3.1.1.2. 整体结构
// Block definition
message Block {
// header of the block
BlockHeader header = 1;
// execution sequence of intra block transactions, generated by proposer
DAG dag = 2;
// transaction list in this block
repeated Transaction txs = 3;
// stores the voting information of the current block
// not included in block hash value calculation
AdditionalData additional_data = 4;
}
// block additional data
message AdditionalData {
// extra data, with map type, excluded in hash calculation
map<string, bytes> extra_data = 1;
}
// transaction execution sequence
// Using adjacency table storage
message DAG {
// Neighbor node: related party transactions with reading and writing conflicts
message Neighbor {
repeated uint32 neighbors = 1;
}
// sequence number of transaction topological sort
//the sequence number of the transaction topological sort associated with the transaction
repeated Neighbor vertexes = 2;
}
Header:区块头
Dag:块内交易的执行依赖顺序,由Proposer生成,如果为空则表示本区块的所有交易都可以并行执行,不存在前后依赖关系
Txs:块内交易列表
AdditionalData:区块产生以后附加的数据,不参与区块的散列值计算。可用于存储当前区块的投票信息,交易过滤等,具体内容根据链上配置的内容而决定
3.1.1.3. 区块头
// header of the block
message BlockHeader {
// block version
uint32 block_version = 1;
// config block or normal block or other else
BlockType block_type = 2;
// blockchain identifier
string chain_id = 3;
// block height
uint64 block_height = 4;
// block hash (block identifier)
bytes block_hash = 5;
// previous block hash
bytes pre_block_hash = 6;
// previous config block height, used to trace and check if chain config is valid
uint64 pre_conf_height = 7;
// count of transactions
uint32 tx_count = 8;
// merkle root of transactions
// used to verify the existence of this transactions
bytes tx_root = 9;
// Save the DAG feature summary, and hash the DAG after Pb serialization
// hash of serialized DAG
bytes dag_hash = 10;
// The root hash of Merkle tree generated by read_write_set_digest in the result of each transaction in the block
// used to verify the read-write set of the block
bytes rw_set_root = 11;
// the time stamp of the block
int64 block_timestamp = 12;
// consensus parameters
// used to store information, include in block hash calculation
bytes consensus_args = 13;
// proposal node identifier
accesscontrol.Member proposer = 14;
// signature of proposer
bytes signature = 15;
}
// BlockType specify block pack txs type
enum BlockType {
// Normal block, pack multi txs into one block
NORMAL_BLOCK = 0;
// Config block, only include 1 chain config update tx in this block
CONFIG_BLOCK = 1;
// Sql Contract init or upgrade block, only include 1 sql contract init or upgrade tx in this block
CONTRACT_MGR_BLOCK = 2;
// block.Txs[0] is a coinbase tx
HAS_COINBASE = 4;
}
BlockVersion:区块版本
BlockType: 区块的类型,按打包的交易类型,分为普通区块、链配置区块、合约管理区块和拥有Coinbase交易的区块等。
ChainId:链标识,用于区分不同的链,在多子链的情况下可区分不同的子链
BlockHeight:区块高度,创世区块高度为0
BlockHash:本区块的散列值
PreBlockHash:上个区块的散列值
PreConfHeight:上一次修改链配置的区块高度,在这个高度的区块中,只存在一笔交易,为配置交易,其中保存了区块链的配置信息,包括本区块应该采用的共识算法,加密算法等
TxCount:交易数量
TxRoot:区块交易的Merkle Root
DagHash:当前区块Dag的散列值
RwSetRoot:区块读写集的Merkle Root
BlockTimestamp:区块的时间戳
ConsensusArgs:共识参数
Proposer:区块的生成者标识
Signature:区块生成者的签名
3.1.2. 交易结构
3.1.2.1. 交易结构示意图
![](../images/DataStructure-Transaction.png)
3.1.2.2. 交易结构定义
// a transaction includes request and its result
message Transaction {
// payload
Payload payload = 1;
// sender account and signature
EndorsementEntry sender = 2;
// endorser accounts and signatures
repeated EndorsementEntry endorsers = 3;
// result of the transaction
Result result = 4;
}
Payload:交易的载荷数据,交易的核心信息
Sender:交易的发起者信息和签名信息
Endorsers:多签情况下,多个背书人的身份信息和其签名信息
Result:交易结果,由Proposer生成区块时进行计算、赋值
3.1.2.3. 交易载荷
//transaction payload
message Payload {
// blockchain identifier
string chain_id = 1;
// transaction type
TxType tx_type = 2;
// transaction id set by sender, should be unique
string tx_id = 3;
// transaction timestamp, in unix timestamp format, seconds
int64 timestamp = 4;
// expiration timestamp in unix timestamp format
// after that the transaction is invalid if it is not included in block yet
int64 expiration_time = 5;
// smart contract name
string contract_name = 6;
// invoke method
string method = 7;
// invoke parameters in k-v format
repeated KeyValuePair parameters = 8;
// sequence number, default is 0
uint64 sequence = 9;
// gas price+gas limit; fee; timeout seconds;
bytes limit = 10;
}
// transaction type definition
enum TxType {
// call a pre created contract, tx included in block
INVOKE_CONTRACT = 0;
// query a pre-created contract, tx not included in block
QUERY_CONTRACT = 1;
// subscribe block info,tx info and contract info. tx not included in block
SUBSCRIBE = 2;
// archive/restore block, tx not included in block
ARCHIVE = 3;
}
// a k-v pair
message KeyValuePair {
string key = 1;
bytes value = 2;
}
ChainId:链标识,表明本交易是针对哪条链的,防止一个交易在多个链中被打包
TxType:交易类型,目前有4种,合约调用、合约查询、订阅、归档。其中只有合约调用会被打包上链,另外几种只用于SDK与节点之间的通信协议
TxId:交易ID,用做该交易的全局唯一性标识
Timestamp:生成交易的unix时间戳,当proposer从交易池获取交易时,用来检测该交易是否超时未上链;如果超时,该交易将从交易池删除
ExpirationTime:交易的到期的unix时间,单位秒,不为0时,交易必须在该时间戳之前被打包上链
ContractName:被调用的合约名
Method:被调用的合约方法名
Parameters:调用合约方法时传入的参数列表,为Key/Value列表类型
Sequence:交易的顺序号,0表示该交易没有顺序要求;大于0则按交易发起人顺序递增
Limit:交易执行的限制,对于有Gas限制的场景,可以是GasLimit+GasPrice,对于有超时限制的场景,可以是Timeout毫秒数
3.1.2.4. 交易发送者与签名
// endorsement info, including a signer and his signature
message EndorsementEntry {
// signer
accesscontrol.Member signer = 1;
// signature
bytes signature = 2;
}
// member of blockchain
message Member {
// organization identifier of the member
string org_id = 1;
// member type
MemberType member_type = 2;
// member identity related info bytes
bytes member_info = 3;
}
enum MemberType {
//X509 cert
CERT = 0;
//cert hash
CERT_HASH = 1;
//public key
PUBLIC_KEY = 2;
//did
DID = 3;
}
Sender:交易发送者信息,由Signer和Signature组成
Signer为Member类型,主要包含以下信息:
OrgId:成员所属机构编号
MemberType:成员的类型,主要有:X509证书、证书哈希、公钥、DID等几种类型。
MemberInfo:成员的身份信息,可以是证书信息也可以是证书哈希,或者是公钥、DID等,依赖于MemberType字段
Signature:交易发送者对Payload的签名,具体签名算法取决与链配置和X509证书中的签名算法
3.1.2.5. 交易结果
// tx result, part of a transaction in block
message Result {
// response code
TxStatusCode code = 1;
// returned data, set in smart contract
ContractResult contract_result = 2;
// hash of the transaction's read-write set
bytes rw_set_hash = 3;
string message = 4;
}
// invoke user contract method return UserContractReturnPayload
// Unmarshal from TransactResult.TxResponse.payload
message ContractResult {
// user contract defined return code, 0-ok, >0 user define error code. for example, insufficient balance in token transfer
uint32 code = 1;
// user contract defined result
bytes result = 2;
// user contract defined result message
string message = 3;
// gas used by current contract(include contract call)
uint64 gas_used = 4;
// contract events
repeated ContractEvent contract_event = 5;
}
// contract event saved in block chain
message ContractEvent {
string topic = 1;
string tx_id = 2;
string contract_name = 3;
string contract_version = 4;
repeated string event_data = 5;
}
TxStatusCode:交易执行结果的状态
ContractResult:合约执行结果
Code:用户自定义的合约执行结果的状态,0表示成功,>0表示异常
Result:合约执行返回的结果
Message:合约执行后的消息
GasUsed:合约执行消耗的Gas数量
ContractEvent:合约执行产生的事件日志
RwSetHash:交易执行结果的读写集哈希
Message:合约执行前的消息
3.1.3. 交易请求结构
// transaction request proposed by user
message TxRequest {
// payload
Payload payload = 1;
// sender account and sender's signature
EndorsementEntry sender = 2;
// endorsers account and signatures
repeated EndorsementEntry endorsers = 3;
}
用户发起一个交易请求的完整结构,包括:
Payload:交易的载荷数据,交易的核心信息
Sender:交易的发起者信息和发起者对Payload的签名信息
Endorsers:多签情况下,多个背书人的身份信息和其对Payload的签名信息
3.1.4. 交易响应结构
// tx request - tx response, only for RPC response
message TxResponse {
// response code
TxStatusCode code = 1;
// response message
string message = 2;
// returned data, set in smart contract
ContractResult contract_result = 3;
//tx id of request
string tx_id = 4;
}
Code:交易执行结果的状态
Message:交易执行后,合约输出的消息
ContractResult:合约执行结果
TxId:对应的交易ID
3.1.5. 交易执行结果的读写集
3.1.5.1. 读写集
// TxRWSet describes all the operations of a transaction on ledger
message TxRWSet {
// transaction identifier
string tx_id = 1;
// read set
repeated TxRead tx_reads = 2;
// write set
repeated TxWrite tx_writes = 3;
}
读写集为交易合约正常执行后对其世界状态的改变情况的反应,主要包括:
TxId 本读写集是由哪个交易产生的
TxRead 读集列表
TxWrite 写集列表
3.1.5.2. 读对象
读集主要用于在并发执行合约交易后判断并发的交易之间是否存在数据(版本)冲突,如果冲突则需要在DAG结构中反映交易之间的依赖情况,并调整冲突交易的执行顺序,重新执行合约。
// TxRead describes a read operation on a key
message TxRead {
// read key
bytes key = 1;
// the value of the key
bytes value = 2;
// contract name, used in cross-contract calls
// set to null if only the contract in transaction request is called
string contract_name = 3;
// read key version
KeyVersion version = 4;
}
一条交易读主要包括:
ContractName 本读记录是读的哪个合约的状态数据
Key 本记录读取的状态键值信息
Version 读取到的版本
Value 读取到的值,后期考虑将Value移除,只需要依靠Version即可进行冲突判断。
3.1.5.3. 写对象
交易正常执行完毕后,如果世界状态发生了更改,那么写集就会记录详细的更改记录。
// TxRead describes a write/delete operation on a key
message TxWrite {
// write key
bytes key = 1;
// write value
bytes value = 2;
// contract name, used in cross-contract calls
// set to null if only the contract in transaction request is called
string contract_name = 3;
}
交易写包括以下内容:
ContractName 对哪个合约的状态数据进行了更改
Key 被修改的状态键值
Value 修改后的状态值