主子链

1. 引言

1.1 背景

ChainSQL 3.0 之前的版本中,所有节点都属于一个链,所有的业务都在这条链上进行,所有的节点都会同步相同的数据,这会存在以下问题:

  • 数据冗余:随着业务量的增加,数据会越来越大,每个节点都会同步和存储一些不必要的数据,这增加了数据同步的压力、数据存储的压力和数据处理的压力

  • 安全隐患:网络中所有的节点都能读取到所有的数据,一些敏感数据可能分发给其他不应该访问这些数据的节点,这会带来数据安全隐患

1.2 目标

通过实现ChainSQL主子链功能,实现以下目标:

  1. 单个ChainSQL中节点可支持多条子链同时运行

  2. 子链之间数据隔离(包括存储,网络通讯等)

  3. 子链创建时可选择是否继承主链状态

  4. 通过主链实现对子链共识节点的去中心化管理

在ChainSQL主子链的设计中,主链负责对多条子链共享的数据进行初始化,子链负责实现具体业务。

2. 总体设计

ChainSQL主子链有以下3个特性:

  1. 子链可选择继承主链账户状态

  2. 通过主链对子链的共识节点进行治理

  3. 可通过多方签名方式发送子链相关交易,子链节点执行建链操作时不需要再进行加入子链的确认

2.1 主子链关系图

子链可选择继承主链账户状态,也可以选择创建全新的子链

Schema

2.2 子链数据隔离

一个ChainSQL节点可以同时支持主链(必选)与多条子链(可选)的运行,每条子链都有独立的P2P网络、交易池、共识、存储以及数据库模块:

SchemaIsolation

2.3 子链继承主链状态

子链继承主链状态实现步骤如下:

  1. 子链创世块的状态树根Hash与继承的主链区块状态树根Hash相同;

  2. 子链创世块的父区块Hash为继承的主链区块Hash;

  3. 将子链创世块相关的数据完整地存储到子链;

SchemaSuccession

3.结构定义

3.1 新增Schema链上数据结构

字段名

类型

描述

Account

String

建子链的账户ID

SchemaName

String

子链名称

SchemaStrategy

Int

建链策略(1,2)

SchemaAdmin

String

子链管理员(可选)

AnchorLedgerHash

String

要锚定的主链区块Hash(依赖chain_strategy=2)

Validators

Array

子链的信任列表(all)

PeerList

Array

邻接节点连接方式

其中,ChainStrategy取值意义如下:

  • 1 :创建全新子链

  • 2 :子链继承主链状态

Validator的元素结构为:

字段名

类型

描述

PublicKey

String

建子链的账户ID

Signed

BOOL

是否参与了建链交易多方签名

  • Signed字段值是由交易推断出来的:只有SchemaCreate交易是多方签名交易且交易中Validators字段某一公钥对交易进行了签名,Signed值才会置为1,否则置为0。

  • 如果选择子链继承主链状态,则子链继承主链所有状态,并且子链创世区块的父区块hash为锚定的主链区块hash

3.2.新增交易类型

3.2.1 子链创建交易

SchemaCreate

字段名

类型

描述

Account

String

建子链的账户ID

TransactionType

String

交易类型:SchemaCreate

SchemaName

String

子链名称

SchemaStrategy

Int

建链策略(1,2)

SchemaAdmin

String

子链管理员(可选)

AnchorLedgerHash

String

要锚定的主链区块Hash(依赖chain_strategy=2)

Validators

Array

子链的信任列表(all)

PeerList

Array

邻接节点连接方式

3.2.2.子链修改共识列表交易

SchemaModify

字段名

类型

描述

Account

String

管理员账户/建链账户(多方签名中使用)

TransactionType

String

交易类型:SchemaModify

OpType

Int

操作码(1为增加节点,2为删除节点)

SchemaID

String

子链ID

Validators

Array

子链的信任列表(all)

PeerList

Array

邻接节点连接方式

4.详细流程

4.1子链的创建

4.1.1节点确认加入

ChainSQL 3.0 中,任何账户都可以创建子链,那就存在一个问题,子链中的节点如果不想加入某条子链,而被某个账户建子链时加入到共识列表中,怎么办? ChainSQL中通过下面三种方案来解决这一问题:

  1. 对子链创建交易直接使用多方签名

  2. 节点可配置自动加入子链

  3. 节点不配置自动加入子链,通过命令主动加入

4.1.1.1 多方签名交易建链
  1. 交易发送方设置多方签名列表(签名列表中每个地址用子链参与节点的validation_seed生成)

  2. 构造建链交易JSON

  3. 子持有者对建链交易签名

  4. 构造多方签名交易,并发送

  5. 节点收链节点私钥到建链交易,检查交易中validators数组中哪些公钥参与了多方签名,并在新建的SLE结构中将对应项的Signed字段置为true

4.1.2 新建存储

这里分两种情况:

  1. 不继承主链状态,子链创世块与主链创世块生成规则相同

  2. 继承主链状态,子链创世块的父区块hash为继承的主链区块hash,子链创世块中有与主链中锚定的区块相同的全局世界状态

4.2子链的修改

4.2.1 有管理员

在建链时,如果指定了管理员账户,那么只有管理员账户可直接发送增删节点的交易

对于节点增加

  • 新增节点仍需要配置自动加入子链或者在命令行发送命令加入子链

  • 其它已存在节点在交易共识成功后直接执行增加validator的操作

对于节点删除

  • 被删除节点在监测到修改后停止参与子链

  • 其它节点在交易共识成功后执行删除validator的操作

4.2.2 无管理员

  • 未指定管理员的情况下,只有子链创建账户可以通过多方签名交易发送增删节点的交易。任意一个收集到当前unl_list中多数签名的 SchemaModify 交易都可实现节点增删。

  • 新增节点仍需要配置自动加入子链或者在命令行发送命令加入子链

5. 架构调整

ChainSQL将原有代码结构进行了拆分重组,将公共模块如 线程池、日志模块等还放在Application管理类中,而将 节点管理、交易池、共识、存储等子链相关的模块放到Schema模块中, 通过SchemaManager来对子链进行管理:

SchemaArchitecture

6.子链日志输出

所有子链日志都在同一个文件中,为了避免混淆,用16进制的SchemaId取前4位作为子链的标识,如:

SchemaId= 001814BCCB1B1D0598366F033091DE9D7CC41419583A4F5CD04ABC36BE210163

日志中会有 [0018] 作为子链的标识:

2020-Oct-26 03:46:04.4880969 [0018]OrderBookDB:DBG Advancing from 0 to 2

而主链的日志以及 [0000] 作为标识