• 3. 核心数据结构
    • 3.1. 背景
    • 3.2. 核心数据结构
      • 3.2.1. 区块
      • 3.2.2. 交易
      • 3.2.3. UTXO
      • 3.2.4. 读写集

    3. 核心数据结构

    3.1. 背景

    众所周知,程序=数据结构+算法,了解一个程序的数据结构有助于掌握一个程序的关键设计。本文从背景、功能以及各个字段的用意来剖析XuperChain底层核心数据结构,从而方便XuperChain开发者以及用户更深入地了解XuperChain底层框架的核心数据结构的设计缘由,有助于提高XuperChain开发者更高效的开发,有助于XuperChain用户更好的使用XuperChain来服务自己的业务。

    3.2. 核心数据结构

    涉及到的核心数据结构包括:区块、交易、UTXO、读写集。

    3.2.1. 区块

    • 背景:所谓区块链,简单来说就是不同的区块以DAG方式链接起来形成的链。因此,区块是区块链的基本单元。
    • 功能:区块是区块链的基本单元,通常为了提高区块链网络的吞吐,矿工会在一个区块中打包若干个交易。一个区块通常由区块头以及区块体组成。../_images/block-img.png
    • 代码:区块的Proto如下
    1. message InternalBlock {
    2. // block version
    3. // 区块版本
    4. int32 version = 1;
    5. // Random number used to avoid replay attacks
    6. // 随机数,用来避免重放攻击
    7. int32 nonce = 2;
    8. // blockid generate the hash sign of the block used by sha256
    9. // 区块的唯一标识
    10. bytes blockid = 3;
    11. // pre_hash is the parent blockid of the block
    12. // 区块的前置依赖区块ID
    13. bytes pre_hash = 4;
    14. // The miner id
    15. // 矿工ID
    16. bytes proposer = 5;
    17. // 矿工对区块的签名
    18. // The sign which miner signed: blockid + nonce + timestamp
    19. bytes sign = 6;
    20. // The pk of the miner
    21. // 矿工公钥
    22. bytes pubkey = 7;
    23. // The Merkle Tree root
    24. // 默克尔树树根
    25. bytes merkle_root = 8;
    26. // The height of the blockchain
    27. // 区块所在高度
    28. int64 height = 9;
    29. // Timestamp of the block
    30. // 打包区块的时间戳
    31. int64 timestamp = 10;
    32. // Transactions of the block, only txid stored on kv, the detail information
    33. // stored in another table
    34. // 交易内容
    35. repeated Transaction transactions = 11;
    36. // The transaction count of the block
    37. // 区块中包含的交易数量
    38. int32 tx_count = 12;
    39. // 所有交易hash的merkle tree
    40. repeated bytes merkle_tree = 13;
    41. // 采用DPOS共识算法时,当前是第几轮
    42. int64 curTerm = 16;
    43. int64 curBlockNum = 17;
    44. // 区块中执行失败的交易以及对应的失败原因
    45. map<string, string> failed_txs = 18; // txid -> failed reason
    46. // 采用POW共识算法时,对应的挖矿难度值
    47. int32 targetBits = 19;
    48. // 下面的属性会动态变化
    49. // If the block is on the trunk
    50. // 该区块是否在主干上
    51. bool in_trunk = 14;
    52. // Next next block which on trunk
    53. // 当前区块的后继区块ID
    54. bytes next_hash = 15;
    55. }

    3.2.2. 交易

    • 背景:区块链网络中的每个节点都是一个状态机,为了给每个节点传递状态,系统引入了交易,作为区块链网络状态更改的最小操作单元。
    • 功能:通常表现为普通转账以及智能合约调用。
    • 代码:交易的Proto如下
    1. message Transaction {
    2. // txid is the id of this transaction
    3. // 交易的唯一标识
    4. bytes txid = 1;
    5. // the blockid the transaction belong to
    6. // 交易被打包在哪个区块中
    7. bytes blockid = 2;
    8. // Transaction input list
    9. // UTXO来源
    10. repeated TxInput tx_inputs = 3;
    11. // Transaction output list
    12. // UTXO去处
    13. repeated TxOutput tx_outputs = 4;
    14. // Transaction description or system contract
    15. // 交易内容描述或系统合约
    16. bytes desc = 6;
    17. // Mining rewards
    18. // 矿工奖励
    19. bool coinbase = 7;
    20. // Random number used to avoid replay attacks
    21. // 随机数
    22. string nonce = 8;
    23. // Timestamp to launch the transaction
    24. // 发起交易的时间戳
    25. int64 timestamp = 9;
    26. // tx format version; tx格式版本号
    27. int32 version = 10;
    28. // auto generated tx
    29. // 该交易是否属于系统自动生成的交易
    30. bool autogen = 11;
    31. // 读写集中的读集
    32. repeated TxInputExt tx_inputs_ext = 23;
    33. // 读写集中的写集
    34. repeated TxOutputExt tx_outputs_ext = 24;
    35. // 该交易包含的合约调用请求
    36. repeated InvokeRequest contract_requests = 25;
    37. // 权限系统新增字段
    38. // 交易发起者, 可以是一个Address或者一个Account
    39. string initiator = 26;
    40. // 交易发起需要被收集签名的AddressURL集合信息,包括用于utxo转账和用于合约调用
    41. repeated string auth_require = 27;
    42. // 交易发起者对交易元数据签名,签名的内容包括auth_require字段
    43. repeated SignatureInfo initiator_signs = 28;
    44. // 收集到的签名
    45. repeated SignatureInfo auth_require_signs = 29;
    46. // 节点收到tx的时间戳,不参与签名
    47. int64 received_timestamp = 30;
    48. // 统一签名(支持多重签名/环签名等,与initiator_signs/auth_require_signs不同时使用)
    49. XuperSignature xuper_sign = 31;
    50. }

    3.2.3. UTXO

    • 背景:区块链中比较常见的两种操作,包括普通转账以及合约调用,这两种操作都涉及到了数据状态的引用以及更新。为了描述普通转账涉及到的数据状态的引用以及更新,引入了UTXO(Unspent Transaction Output)。
    • 功能:一种记账方式,用来描述普通转账时涉及到的数据状态的引用以及更新。通常由转账来源数据(UtxoInput)以及转账去处数据(UtxoOutput)组成。../_images/tx-img.png
    • 代码:UTXO的Proto如下
    1. message Utxo {
    2. // 转账数量
    3. bytes amount = 1;
    4. // 转给谁
    5. bytes toAddr = 2;
    6. // 转给谁的公钥
    7. bytes toPubkey = 3;
    8. // 该Utxo属于哪一个交易
    9. bytes refTxid = 4;
    10. // 该Utxo数据哪一个交易的哪一个offset
    11. int32 refOffset = 5;
    12. }
    13. // UtxoInput query info to query utxos
    14. // UTXO的转账来源
    15. message UtxoInput {
    16. Header header = 1;
    17. // which bcname to select
    18. // UTXO来源属于哪一条链
    19. string bcname = 2;
    20. // address to select
    21. // UTXO来源属于哪个address
    22. string address = 3;
    23. // publickey of the address
    24. // UTXO来源对应的公钥
    25. string publickey = 4;
    26. // totalNeed refer the total need utxos to select
    27. // 需要的UTXO总额
    28. string totalNeed = 5;
    29. // userSign of input
    30. // UTXO来源的签名
    31. bytes userSign = 7;
    32. // need lock
    33. // 该UTXO是否需要锁定(内存级别锁定)
    34. bool needLock = 8;
    35. }
    36. // UtxoOutput query results
    37. // UTXO的转账去处
    38. message UtxoOutput {
    39. Header header = 1;
    40. // utxo list
    41. // UTXO去处
    42. repeated Utxo utxoList = 2;
    43. // total selected amount
    44. // UTXO去处总额
    45. string totalSelected = 3;
    46. }

    3.2.4. 读写集

    • 背景:区块链中比较常见的两种操作,包括普通转账以及合约调用,这两种操作都涉及到了数据状态的引用以及更新。为了描述合约调用涉及到的数据状态的引用以及更新,引入了读写集。
    • 功能:一种用来描述合约调用时涉及到的数据状态的引用以及更新的技术。通常由读集(TxInputExt)以及写集(TxOutputExt)组成。../_images/xupermodel1.png
    • 代码:读写集的Proto如下
    1. // 扩展输入
    2. message TxInputExt {
    3. // 读集属于哪一个bucket
    4. string bucket = 1;
    5. // 读集对应的key
    6. bytes key = 2;
    7. // 读集属于哪一个txid
    8. bytes ref_txid = 3;
    9. // 读集属于哪一个txid的哪一个offset
    10. int32 ref_offset = 4;
    11. }
    12. // 扩展输出
    13. message TxOutputExt {
    14. // 写集属于哪一个bucket
    15. string bucket = 1;
    16. // 写集对应的key
    17. bytes key = 2;
    18. // 写集对应的value
    19. bytes value = 3;
    20. }