简介
高性能,通过原创的XuperModel模型,真正实现了智能合约的并行执行和验证,通过自研的WASM虚拟机,做到了指令集级别的极致优化。 在架构方面,其可插拔、插件化的设计使得用户可以方便选择适合自己业务场景的解决方案,通过独有的XuperBridge技术,可插拔多语言虚拟机,从而支持丰富的合约开发语言。在网络能力方面, XuperChain具备全球化部署能力,节点通信基于加密的P2P网络,支持广域网超大规模节点,且底层账本支持分叉管理,自动收敛一致性,TDPOS算法确保了大规模节点下的快速共识。在账户安全方面,XuperChain内置了多私钥保护的账户体系,支持权重累计、集合运算等灵活的策略。
模块
- 存储: 底层存储基于KV数据库,存储的数据包括区块数据、交易数据、账户余额、DPOS投票数据、合约账号数据、智能合约数据等,上链的数据全部持久化到底层存储。不同的链,存储独立。底层存储支持可插拔。
- 网络: 负责交易数据的网络传播和广播、节点发现和维护。以P2P通信为基础,实现全分布式结构化拓扑网络结构,数据传输全程加密。局域网穿透技术采用NAT方案,同一条流保持长连接且复用。多条链复用同一个p2p网络。
- 共识: 共识模块用于解决交易上链顺序问题,过滤无效交易并达成全网一致。XuperChain实现了更加高效的DPOS共识算法。支持可插拔,从而可以支持不同的业务场景。
- 密码学: 用于构造和验证区块、交易的完整性,采用非对称加密算法生成公私钥、地址。匿名性较好。支持可插拔,从而可以支持不同的业务场景。
- 智能合约: 自研并实现了一套智能合约虚拟机XVM,支持丰富的开发语言,智能合约之间并发执行,支持执行消耗资源,避免恶意攻击。
- 提案: 一种解决系统升级问题的机制。比如修改区块大小,升级共识算法。提案整个过程涉及到发起提案、参与投票、投票生效三个阶段。
- 账号与权限: 为了满足合约调用的权限控制,保证XuperChain网络的健康运转,自研并实现了一套基于账户的去中心化的合约权限系统。支持权重累计、集合运算等灵活的策略,可以满足不同的业务场景。
XuperChain是百度自研的一套区块链解决方案,采用经典的UTXO记账模式,并且支持丰富的智能合约开发语言,交易处理支持并发执行,拥有完善的账户与权限体系,具有可插拔共识机制。
关键概念
超级节点
超级节点的实体可以是一个机构,一家公司或政府部门,对外呈现是一个节点,其内部是分布式网络能力,超级节点参与记账权竞争,保证了全网运行的效率,利用超级计算机和分布式架构,突破单机限制,解决区块链网络算力和存储问题,使节点具备无限的计算力和存储力。 - 存储支持: 超级节点会存储所有的历史事务的完整信息,如何支撑 PB 级别的容量非常具有挑战。 XuperChain底层 KV 存储引擎主要有以下几个特点:
事务性表格系统:通过前缀编码的平展化,支持多链 + 多表,且能保证跨链事务的原子性;
多盘技术:实现 KV 存储引擎到底层文件系统的虚拟映射层,支持单机多盘存储,从而支撑大容量数据存储; - 计算支持: 非 POW 的共识机制下,超级节点的主要计算量为交易上链和合约执行。很多区块链软件对交易的执行以及合约的执行都是串行执行的,优化到极致也只能使用单核,对硬件的利用率很低。超级节点采用多核并行计算与分布式计算相结合的方式以提升计算效率。
多核并行计算:XuperChain通过智能合约的依赖关系将待打包的事务构造出 N个DAG。每个DAG的交易和合约执行都是并行跑在多个 CPU 核上, DAG 内部无路径依赖的节点也可以并行执行,从而可以最大化 CPU 的利用率,突破系统吞吐瓶颈。平行链和可回归侧链技术也能有效的利用多核并发;
分布式计算:XuperChain未来构建事务执行的分布式调度集群,链内并行事务和多链事务可分发给调度集群执行,从而利用分布式计算的扩展能力。
链内并行
当下区块链技术的实现是将所有事物打包后顺序执行。随着智能合约越来越复杂,如果顺序执行智能合约,高并发度将难以实现。顺序执行智能合约不能充分利用多核和分布式的计算能力,造成资源浪费。 XuperChain 将合约中互相依赖的事物挖掘成DAG图的形式,便于并发的执行。依据生成的DAG图来控制事务的并发,最大化资源的利用,提高合约效率。
XuperModel
XuperChain能够支持合约链内并行的很大的原因是由于其底层自研的XuperModel数据模型。XuperModel是一个带版本的存储模型,支持读写集生成。该模型是比特币utxo模型的一个演变。在比特币的utxo模型中,每个交易都需要在输入字段中引用早期交易的输出,以证明资金来源。同样,在XuperModel中,每个事务读取的数据需要引用上一个事务写入的数据。在XuperModel中,事务的输入表示在执行智能合约期间读取的数据源,即事务的输出来源。事务的输出表示事务写入状态数据库的数据,这些数据在未来事务执行智能合约时将被引用。
[img D0772C24-D33C-4937-85DD-38A54580AE18]
为了在运行时获取合约的读写集,在预执行每个合约时XuperModel为其提供智能缓存。该缓存对状态数据库是只读的,它可以为合约的预执行生成读写集和结果。验证合约时,验证节点根据事务内容初始化缓存实例。节点将再次执行一次合约,但此时合约只能从读集读取数据。同样,写入数据也会在写入集中生效。当验证完生成的写集和事务携带的写集一致时合约验证通过,将事务写入账本。 cache的原理如下所示,图中左边部分是合约预执行时的示意图,右边部分是合约验证时的示意图:
[img FD94EB99-221E-45A0-8707-8A5B6FF95164]
XuperBridge
为所有合约提供统一的链上数据访问接口,从抽象方式上类似于应用程序,内核代码是一份,应用程序可以用各种语言实现。类比到合约上就是各种合约的功能,KV访问、QueryBlock、QueryTx等,这些请求都会通过跟xchain通信的方式来实现,这样在其上实现的各种合约的虚拟机只需做纯粹的无状态合约代码执行。
[img F6015C7C-1C89-4003-8AF4-4187547C36E0]
合约与xchain进程的双向通信
xchain进程需要调用合约虚拟机来执行具体的合约代码,合约虚拟机也需要跟xchain进程通信来进行具体的系统调用,如KV获取等,这是一个双向通信的过程。
[img B6CBEB0F-21F8-4604-8E67-AD1BA2A369C8]
这种双向通信在不同虚拟机里面有不同的实现, 在native合约里面由于合约是跑在docker容器里面的独立进程,因此牵扯到跨进程通信,这里选用了unix socket作为跨进程通信的传输层,xchain在启动合约进程的时候把syscall的socket地址以及合约进程的socket地址传递给合约进程,合约进程一方面监听在unix socket上等待xchain调用自己运行合约代码,另一方面通过xchain的unix socket创建一个指向xchain syscall服务的grpc客户端来进行系统调用。
[img BD14D390-C42B-42E4-91E7-C80FDCF41351]
在WASM虚拟机里面情况有所不同,WASM虚拟机是以library的方式链接到xchain二进制里面,所以虚拟机和xchain在一个进程空间,通信是在xchain和WASM虚拟机之间进行的,这里牵扯到xchain的数据跟虚拟机里面数据的交换,在实现上是通过WASM自己的模块机制实现的,xchain实现了一个虚拟的WASM模块,合约代码执行到外部模块调用的时候就转到对应的xchain函数调用,由于xchain和合约代码的地址空间不一样,还是牵扯到序列化和反序列化的动作。
[img 0D64535A-3613-4F0C-A1AA-CCD9E517B213]
合约上下文
每次合约运行的时候都会有一个伴随合约执行的上下文(context)对象,里面保存了合约的kv cache对象,运行参数,输出结果等。用于隔离多个合约的执行,也便于合约的并发执行。
Context的创建和销毁
context在合约虚拟机每次执行合约的时候创建。 每个context都有一个context id,这个id由合约虚拟机维护,在xchain启动的时候置0,每次创建一个context对象加1,合约虚拟机保存了context id到context对象的映射。 context id会传递给合约虚拟机,在Docker里面即是合约进程,在之后的合约发起KV调用过程中需要带上这个context id来标识本次合约调用以找到对应的context对象。
context的销毁时机比较重要,因为我们还需要从context对象里面获取合约执行过程中的Response以及读写集,因此有两种解决方案,一种是由调用合约的地方管理,这个是xuper3里面做的,一种是统一销毁,这个是目前的做法,在打包成块结束调用Finalize的时候统一销毁所有在这个块里面的合约context对象。
合约上下文的操作
- NewContext,创建一个context,需要合约的参数等信息。
- Invoke,运行一个context,这一步是执行合约的过程,合约执行的结果会存储在context里面。
- Release,销毁context,context持有的所有资源得到释放。
XVM虚拟机
XVM为合约提供一个稳定的沙盒运行环境,有如下目标: - 隔离性,合约运行环境和xchain运行环境互不影响,合约的崩溃不影响xchain。
- 确定性,合约可以访问链上资源,但不能访问宿主机资源,保证在确定的输入下有确定的输出
- 可停止性,设置资源quota,合约对资源的使用超quota自动停止
- 可以统计合约的资源使用情况,如CPU,内存等
- 运行速度尽量快。
WASM
WASM是WebAssembly的缩写,是一种运行在浏览器上的字节码,用于解决js在浏览器上的性能不足的问题。 WASM的指令跟机器码很相似,因此很多高级语言如C,C++,Go,rust等都可以编译成WASM字节码从而可以运行在浏览器上。 很多性能相关的模块可以通过用C/C++来编写,再编译成WASM来提高性能,如视频解码器,运行在网页的游戏引擎,React的虚拟Dom渲染算法等。
WASM本身只是一个指令集,并没有限定运行环境,因此只要实现相应的解释器,WASM也可以运行在非浏览器环境。 xchain的WASM合约正是这样的应用场景,通过用C++,go等高级语言来编写智能合约,再编译成WASM字节码,最后由XVM虚拟机来运行。 XVM虚拟机在这里就提供了一个WASM的运行环境。
WASM字节码编译加载流程
WASM字节码的运行有两种方式,一种是解释执行,一种是编译成本地指令后再运行。 前者针对每条指令挨个解释执行,后者通过把WASM指令映射到本地指令如(x86)来执行,解释执行优点是启动快,缺点是运行慢,编译执行由于有一个预先编译的过程因此启动速度比较慢,但运行速度很快。
XVM选用的是编译执行模式。
[img 3D5BC3D1-7AFE-47CE-9410-D3C78B0B148E]
加载运行
在了解如何加载运行之前先看下如何使用xvm来发起对合约的调用,首先生成Code对象,Code对象管理静态的指令代码以及合约所需要的符号解析器Resolver。 之后就可以通过实例化Context对象来发起一次合约调用,GasLimit等参数就是在这里传入的。Code和Context的关系类似Docker里面的镜像和容器的关系, 一个是静态的,一个是动态的。
func run(modulePath string, method string, args []string) error {
code, err := exec.NewCode(modulePath, emscripten.NewResolver())
if err != nil {
return err
}
defer code.Release()
ctx, err := exec.NewContext(code, exec.DefaultContextConfig())
if err != nil {
return err
}
ret, err := ctx.Exec(method, []int64{int64(argc), int64(argv)})
fmt.Println(ret)
return err
}
转换后的c代码最终会编译成一个动态链接库来给XVM运行时来使用,在每个生成的动态链接库里面都有如下初始化函数。 这个初始化函数会自动对wasm里面的各个模块进行初始化,包括全局变量、内存、table、外部符号解析等。
typedef struct {
void* user_ctx;
wasm_rt_gas_t gas;
u32 g0;
uint32_t call_stack_depth;
}wasm_rt_handle_t;
void* new_handle(void* user_ctx) {
wasm_rt_handle_t* h = (*g_rt_ops.wasm_rt_malloc)(user_ctx, sizeof(wasm_rt_handle_t));
(h->user_ctx) = user_ctx;
init_globals(h);
init_memory(h);
init_table(h);
return h;
}
语言运行环境
- C++
c++因为没有runtime,因此运行环境相对比较简单,只需要设置基础的堆栈分布以及一些系统函数还有emscripten的运行时函数即可。c++合约的内存分布:
[img 3CBC2FD5-E55C-4ADF-A3C0-6EFD21167D89]
普通调用如何在xvm解释
[img 4CCD76FE-C3D9-4870-AE84-FA5A65F36F79] - go运行环境
[img ECEE6646-A3C4-4F93-8955-6166FA057EC8]
账号权限控制模型
级链需要一套去中心化的,内置的权限系统。
名词解释 - AK(Access Key):具体的一个address,由密码学算法生成一组公私钥对,然后将公钥用指定编码方式压缩为一个地址。
- 账号(Account): 在超级链上部署合约需要有账号, 账号可以绑定一组AK(公钥),并且AK可以有不同的权重。 账号的名字具有唯一性。
- 合约 (Contract): 一段部署在区块链上的可执行字节码,合约的运行会更新区块链的状态。我们允许一个账号部署多个合约。合约的名字具有唯一性。
模型简介
系统会首先识别用户,然后根据被操作对象的ACL( 访问控制列表 )的信息来决定用户的权限:
[img 2ABB85F0-EDA9-46C8-8CA6-7D7D53255342] - 个人账号AK:是指一个具体的地址Addr。用户的创建是离线的行为,可以通过命令行工具或者API进行创建
- 合约账号:超级链智能合约的管理单元。
合约的创建:任何账号或者AK都可以调用系统级智能合约创建账号;创建账号需要指定账号对应的拥有者的地址集(一个账号只有一个地址就对这个Addr拥有完全控制);创建账号需要指定ACL控制策略,用于账号其他管理动作的权限控制;创建账号需要消耗账号资源
账号命名规则XC + 16位数字 + @ + 链名(创建账号的时候,只需要传入16位数,使用账号的时候要用完整账号)
账号管理:根据创建时指定的地址集和权限策略,管理账号其他操作。账号股东加入和删除;账号资产转账;创建合约时消耗账号资源,先将utxo资源打到账号下,通过消耗账号的utxo资源创建合约,验证的逻辑需要走账号的ACL控制;合约method权限模型管理
智能合约:超级链中的一个具体的合约,属于某个账号。账号所属人员允许在账号内部部署合约;可以定义合约管理的权限模型;设置合约方法的权限模型,合约内有一个权限表 {contract.method, permission_model}
合约命名规则:长4~16,只能是数字字母,首字符不能是数字。
实现功能 - 账号权限管理:账号的创建、添加和删除;删除AK、设置AK权重、权限模型
- 合约权限管理,这是合约调用权限:
A.背书阈值:在名单中的AK或Account签名且它们的权重之和大于一定阈值就可以调用合约;
B.AK集合:定义多组AK集合,集合内的AK需要全部签名,集合间只需要有一个集合含有全部签名即可。(AK就是对应一个公私钥对,根据公钥得到的一个addr)
[img F9DC0B7D-2D55-4E53-871A-0B0EAB87D04A]
acl模型
{
"pm": {
"rule": 1,
"acceptValue": 1.0
},
"aksWeight": {
"AK1": 1.0,
"AK2": 1.0
}
}
Rule=1表示签名阈值策略, =2 表示AKSet签名策略
签名的ak对应的weight和>acceptValue,则符合要求
超级链p2p网络
可以将p2p网络简单区分为无结构和结构化两大类:
- 非结构化p2p网络:优点在于可以随意组建,网络局部区域内个体任意分布。对于节点的加入和离开网络也表现的十分稳定。缺点在于,一是公网网络拥塞时传输效率低,二是存在泛洪循环( 泛洪(Flooding)是交换机和网桥使用的一种数据流传递技术,将从某个接口收到的数据流向除该接口之外的所有接口发送出去 ),三是消息风暴问题。
- 结构化的p2p网络:经过精心设计的,目的是为了增加路由效率,提高查询数据的效率,结构化p2p最普遍的实现方案是使用分布式哈希表(DHT)。
NAT技术通过将局域网内的主机地址映射为互联网上的有效ip地址,实现了网络地址的复用,从而部分解决了ip地址短缺的问题。网络中大部分用户处于各类NAT设备之后,导致在p2p网络中两个节点之间直接建立udp或者tcp链接难度比较大,应运而生的是NAT穿透技术。目前主要有两种途径,一种称为打洞,即UDP Punch技术;另一种是利用NAT设备的管理接口,称为UPnP技术。
超级链p2p消息
采用protobuf定义,消息分为两个部分,MessageHeader和MessageData:
[img 4CAD2394-12BF-42E4-8BBC-FC9BE7CF80B7]
消息的定义如下:
// XuperMessage is the message of Xuper p2p server
message XuperMessage {
// MessageHeader is the message header of Xuper p2p server
message MessageHeader {
string version = 1;
// dataCheckSum is the message data checksum, it can be used check where the message have been received
string logid = 2;
string from = 3;
string bcname = 4;
MessageType type = 5;
uint32 dataCheckSum = 6;
ErrorType errorType = 7;
}
// MessageData is the message data of Xuper p2p server
message MessageData {
// msgInfo is the message infomation, use protobuf coding style
bytes msgInfo = 3;
}
MessageHeader Header = 1;
MessageData Data = 2;
}
模块交互图
[img 7543CAFE-F9D7-42CA-9D3D-DCC6CCAA388B]
交易消息处理流程
用户提交的交易消息在网络中传输的处理流程:
[img 0E0B91DF-324E-4033-AA07-B28AF80A16C5]
用户通过RPC将交易提交到网络中个,交易执行成功后会通过p2p模块广播给网络中的其他节点。
身份认证
背景
Xuperchain节点之间存在双重身份:P2P节点ID和Xuperchain address,为了解决节点间的身份互信,防止中间人攻击和消息篡改,节点间需要一种身份认证机制,可以证明对称节点声明的XChain address是真实有效的。
- Xuperchain address:当前节点的address,一般为data/keys/address
- P2P节点ID:当前节点P2P的peer.ID
[img 6870EAD2-8EBB-4949-AC01-45F38B396EB5] - 新建的net.Stream连接,已经完成了ECDH密钥协商流程,因此此时节点间已经是加密连接。
- 连接建立后,增加一步身份认证流程,如果通过,则stream建立成功,加入到streamPool中
其中,身份认证流程如下: - 身份认证流程通过开关控制,可开启和关闭 DefaultIsAuthentication: true or false
- 身份验证支持XChain address的验证方式
- 如果开启身份验证,则身份验证不通过的Stream直接关闭
- 身份验证是使用XChain的私钥对PeerID+XChain地址的SHA256哈希值进行签名,并将PeerID、Xuperchain公钥、Xuperchain地址、签名数据一起传递给对方进行验证
提案和投票机制
[img A1F07F59-F23E-4923-837C-8DAEEEECCE84]
提案和投票机制是区块链系统实现自我进化的关键。系统首次上线后难免遇到很多问题,我们提供提案/投票机制为区块链的社区治理提供便利的工具,以保证未来系统的可持续发展。具体实现方法如下: - Step1:提案者(proposer) 通过发起一个事务声明一个可调用的合约,并约定提案的投票截止高度,生效高度;
- Step2:投票者(voter) 通过发起一个事务来对提案投票,当达到系统约定的投票率并且账本达到合约的生效高度后,合约就会自动被调用;
- Step3:为了防止机制被滥用,被投票的事务的需要冻结参与者的一笔燃料,直到合约生效后解冻。
共识可升级
[img CD493697-BB38-48C5-A537-1BFD2B31407D]
Xuperchain提供可插拔的共识机制,通过提案和投票机制,升级共识算法和参数。
{
"version" : "1",
"predistribution": [
{}
],
"maxblocksize" : "128",
"award" : "1000000",
"decimals" : "8",
"award_decay": {
"height_gap": 31536000,
"ratio": 0.5
},
"genesis_consensus": {
"name": "pow",
"config": {
"defaultTarget": "19", # 默认难度19个0 bits前缀
"adjustHeightGap": "10", # 每10个区块调整一次难度
"expectedPeriod": "15", # 期望15秒一个区块
"maxTarget": "22"
}
}
}
需要将共识切换到TDPOS时。
- 提案者发起提案,提案没有额外的代价,通过命令行的desc选项指定提案用的json即可。
{
"module": "proposal",
"method": "Propose",
"args" : {
"min_vote_percent": 51, # 当投票者冻结的资产占全链的51%以上时生效提案
"stop_vote_height": 120 # 停止计票的高度是:120
},
"trigger": {
"height": 130, # 提案生效高度是:130
"module": "consensus",
"method": "update_consensus",
"args" : {
"name": "tdpos",
"config": {
"proposer_num":"3",
"period":"3000",
"term_gap":"60000",
"alternate_interval": "3000",
"term_interval": "6000",
"block_num":"10",
"vote_unit_price":"1",
"init_proposer": {
"1": ["dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN", "f3prTg9itaZY6m48wXXikXdcxiByW7zgk", "U9sKwFmgJVfzgWcfAG47dKn1kLQTqeZN3"]
}
}
}
}
}
提案命令(会得到一个tx id)
./xchain-cli transfer --to cat data/keys/address
--desc ./myprop.json --amount 1
- 其他用户可以设置自己的冻结资产进行提案投票:
./xchain-cli vote –amount 100000000 –frozen 121 67cc7cd23b7fcbe0a4919d5c581b3fda759da13cdd97414afa7539e221727594 - 查看累计投票金额数量是否满足要求(全链的51%)
./xchain-cli account balance –Z # 可以查看自己被冻结的资产总量。
./xchain-cli status --host localhost:37301 | grep -i total # 查询全链的资产总量。 - 等到打到生效高度,共识已经被切换:
./xchain-cli tdpos status
密码学和隐私保护
哈希函数
加密哈希函数(Hash Function) 是适用于密码学的哈希散列函数,是现代密码学的基本工具。它是一种数学算法,将任意大小的数据(通常称为“消息”)映射到固定大小的二进制串(称之为“散列值”,“散列”或“消息摘要”),并且是单向的功能,即一种实际上不可逆转的功能。理想情况下,查找生成给定哈希的消息的唯一方法是尝试对可能的输入进行暴力搜索,以查看它们是否产生匹配,或使用匹配哈希的彩虹表。 - MD5 : 摘要长度为128bit,由于容易受到碰撞攻击,目前使用越来越少。
- SHA256 : SHA系列哈希算法由美国国家安全局制定,具有多个hash算法标准,可以产生160~512bit不等的哈希摘要。目前在区块链中使用较多的是SHA256,摘要长度为256bit,具有较高的抗碰撞攻击安全性。
- RIPEMD-160 : 产生长度为160bit的摘要串。 相比于美国国家安全局设计的SHA-1和SHA-2算法,RIPEMD-160的设计原理是开放的。
ECC
构建区块链的去中心化交易,需要一种加密算法,使交易发起人使用持有的密钥对交易数据进行数字签名,而交易验证者只需要知道交易发起人的公开信息,即可对交易有效性进行验证,确定该交易确实来自交易发起者。这种场景在密码学中称之为公开密钥加密
,也称之为非对称密钥加密。 - ECIES (Elliptic Curve Integrated Encryption Scheme): 椭圆曲线集成加密算法,主要用于基于椭圆曲线的数据加解密。
- ECDH (Elliptic Curve Diffie–Hellman): 基于Diffie–Hellman算法的一种密钥协商算法,定义了双方如何安全的生成和交换密钥。
- ECDSA (Elliptic Curve Digital Signature Algorithm): 是使用椭圆曲线密码学实现的DSA(数字签名算法),一般发起人对消息摘要使用私钥签名,验证者可以通过公钥对签名有效性进行验证。
多重签名和环签名
多重签名是指在数字签名中,有时需要多个用户对同一个交易进行签名和认证,例如某些合约账户下的数据需要多个人授权才能修改或转账。
在密码学中,通过多重签名可以将多个用户的授权签名信息压缩在同一个签名中,这样相比于每个用户产生一个签名的数据体量会小很多,因此其验签计算、网络传输的资源开销也会少很多。
环签名是一种数字签名技术,环签名的一个安全属性是无法通过计算还原出一组用户中具体使用私钥签名的用户。也就是说,使用环签名技术可以使一组用户中的某一个人对消息进行签名,而并不会泄露签名者是这组用户中的哪个人。环签名与组签名类似,但在两个关键方面有所不同:第一,单个签名具有匿名性; 第二,任何一批用户都可以作为一个组使用,无需额外设置。
在实际使用中,多重签名主要用作多人实名授权的交易,通过产生更小的签名数据提升网络传输和计算效率,而环签名则主要用于对交易隐私保护和匿名性有要求的交易场景中。
Xuperchain中密码学的使用 - 用户公私钥账户
超级链的用户账户体系基于非对称公私钥对,每个用户账户对应这一组公私钥对,并采用一定的哈希算法将公钥摘要成一个字符串作为用户账户地址(address)。
[img 603CD319-AC01-4710-A8F0-46832E0805C0]
超级链中公私钥对使用椭圆曲线算法生成,用户账户地址主要使用SHA256和RIPEMD-160哈希算法生成。
考虑到密钥不具备可读性,为了帮助用户保存密钥,超级链实现了BIP39提案的助记词技术。
助记词的生成过程:首先生成一个长度在128~256bit之间的随机熵,由此在助记词表中选出对应的单词列表,形成助记词。
助记词产生私钥:使用基于口令的密钥派生算法PBKDF2,将上述生成的助记词和用户指定的密钥作为密钥派生算法参数,生成长度为512bit的种子,以此种子作为生成密钥的随机参数,便产生了了从助记词生成的私钥。
通过助记词恢复密钥:由于用户持有生成密钥的助记词和口令,因此在用户私钥遗忘或丢失时,可以通过同样的助记词和口令,执行助记词产生私钥的过程,从而恢复出账户密钥。
数据签名
超级链中,每个交易都需要交易发起人以及交易背书人的签名;在每个块生成时,也需要加上打包块的节点的签名。
交易签名: 基于交易数据摘要,会包含交易输入输出、合约调用、合约读写集、发起人和背书人信息等,并将交易数据序列化后的字节数组使用双重SHA256得到摘要数据,最后对摘要数据用ECDSA或其他数字签名算法产生交易签名。
块签名:基于区块数据摘要,会包含区块元信息如前序块Hash值、交易Merkle树根、打包时间、出块节点等数据,并在序列化后使用双重SHA256得到摘要数据,最后对摘要数据用ECDSA或其他数字签名算法产生区块签名。
[img 24146101-7383-4CCB-B1E4-334957DFFE38]
通信加密
超级链底层采用P2P网络传播交易和区块数据,在一些许可区块链网络场景中,需要对节点间的数据传输进行加密提升安全和隐私性,因此超级链的P2P连接支持基于ECDH的密钥交换算法的TLS连接。 ECDH( 椭圆曲线迪菲-赫尔曼秘钥交换 )的原理是交换双方可以在不共享任何秘密的情况下协商出一个密钥,双方只要知道对方的公钥,就能和自己的私钥通过计算得出同一份数据,而这份数据就可以作为双方接下来对称加密的密钥。
[img 835663E6-9A82-474F-A855-6A589ECC1CCD]
超级链P2P网络通过ECDH建立通信加密通道的过程如上图所示: - 第一阶段是Propose阶段,这一阶段,对等节点间互相交换双方永久公钥PK。
- 第二阶段是Exchange阶段,本质是基于ECDH的密钥交换。双方通过ECC算法随机生成一组临时密钥对(tempPK, tempSK),然后用自己的永久私钥对临时公钥tempPK进行签名并交换。这时,双方可以通过第一步的公钥进行验签,同时拿到供本次会话使用的临时公钥。使用临时公钥的好处是一话一密,即使本次会话密钥泄露也不会导致以前的加密数据被破解。ECDH算法使得双方通过对方的公钥和自己的私钥,可以获得一致的共享密钥SharedKey。
- 第三阶段是Verify阶段。双方使用ShareKey产生两组密钥Key1,Key2分别作为读写密钥,并使用支持的对称加密算法(AES/blowfish)加密传输第一步中发送给对方的Nonce,而接收方则使用刚才协商的密钥对数据解密,并验证Nonce是不是等于第一步中自己发送给对方的值。
插件机制
可插拔架构
超级链从设计之初就以高性能、可插拔的区块链底层技术架构为目标,因此整个超级链在模块化、接口化设计上做了很多的抽象工作。而插件化机制就是服务于超级链可插拔的架构目标,使得所有模块具有同样的可插拔机制,并能满足对模块插件的加载、替换等生命周期的管理。
通过插件化的机制可以实现以下的架构优点:
代码解耦 :插件化机制使超级链的架构框架与各个模块的实现相解耦,模块统一抽象出基本数据结构与框架的交互接口,模块只要符合统一接口即可做到插拔替换。
高可扩展 :用户可以自己实现符合业务需求的模块插件,直接替换插件配置就可以实现业务扩展。
发布灵活 :插件可以单独发布,配合插件生命周期管理甚至可以实现插件的单独更新,而作为插件的开发者也可以自由选择开源发布或者只发布插件二进制文件。
插件框架设计
插件框架用以根据需求创建插件实例,考虑到超级链单进程多链、插件多实例多版本等需求,整体设计:
[img 7DE23B07-B69E-4C1F-933B-7303DD43B7C8] - 模块和插件的定义:
超级链中,一种 模块 是指:包含一组相同数据结构和接口的代码集合,能实现相对独立的功能。 一个模块可以有多种实现,每种实现形成一个 插件 。
模块和插件具有如下约束:
同一种模块,需要抽象出公共数据接口和接口方法;该模块的所有插件,需要实现定义的所有公共接口,并不包含定义接口以外的public接口;每个插件需要实现一个 GetInstance 接口,该接口创建并返回一个插件对象引用,该插件对象包含插件定义的所有公共接口。
因此,我们可以在框架中定义一组公共的数据结构和接口,例如:
package kvstore
type KVStore interface {
Init(string)
Get(string) (string, error)
Set(string, string) error
}
并在插件代码中,引用并实现该公共接口定义,例如:
import "framework/kvstore"
type KVMem struct {
meta kvstore.Meta
data map[string]string
rwmutex sync.RWMutex
}
// 每个插件必须包含此方法,返回一个插件对象
func GetInstance() interface{} {
kvmem := KVMem{}
return &kvmem
}
// 插件需要实现接口定义中的所有方法
func (ys *YourKVStore) Init(conf string) {
// Your code here
}
func (ys *YourKVStore) Get(key string) (string, error) {
// Your code here
}
func (ys *YourKVStore) Set(key string, value string) error {
// Your code here
}
- 配置化管理
插件通过配置文件组织可选插件以及 插件子类型 、插件路径 、版本 等信息。考虑到同一个链中可能需要创建某个插件的多种实例,因此所有的插件都以数组的方式声明该插件不同的子插件类型对应的链接库地址。 - PluginMgr
PluginMgr定义了插件管理的对外接口。
// 根据插件配置文件初始化插件管理对象
func CreateMgr(confPath string) (pm *PluginMgr, err error);
// 指定插件名称和插件子类型,获取该插件的一个实例
func (pm *PluginMgr) CreatePluginInstance(name string, subtype string)
需要插件功能的主逻辑中,要通过 CreateMgr 创建一个PluginMgr的实例,该实例会根据传入的配置文件创建插件实例。
超级链共识框架
区块链共识机制概述
区块链系统多数采用去中心化的分布式设计,节点是分散在各处,系统需要设计一套完善的制度,以维护系统的执行顺序与公平性,统一区块链的版本,并奖励提供资源维护区块链的使用者,以及惩罚恶意的危害者。这样的制度,必须依赖某种方式来证明,是由谁取得了一个区块链的打包权(或称记帐权),并且可以获取打包这一个区块的奖励;又或者是谁意图进行危害,就会获得一定的惩罚,这些都是区块链系统的共识机制需要解决的问题。
随着区块链应用落地场景越来越多,很多适应不同应用场景的共识算法先后被提出。但是在当前的技术背景下,功能过于全面的共识算法无法真正可用。在新一代区块链共识机制的设计过程中,根据实际应用场景,有的放矢的选择去中心化、节能、安全等设计原则,对一些原则支持强弱进行取舍,将一定程度上提升系统的整体运行效率。
我们超级链设计上是一个通用的区块链框架,用户可以方便地进行二次开发定制。超级链的共识模块设计上是一个能够复用底层共识安全的共识框架,用户基于这样的框架可以轻松地定义其自己的链,而不需要考虑底层的共识安全和网络安全。
超级链共识框架概览
[img 7F851C58-60DF-483F-9D12-EA4B20E9C4ED]
上图是超级链共识模块的整体架构图,自底向上主要包括3层:
- 共识公共组件层:该层主要是不同共识可以共用的组件,包括共识公共节点Consensus、Interface、Chained-BFT、GPS原子钟等,它可以为链提供底层的共识安全性保障;
- 共识类型层:中间层为超级链以及支持或者即将支持的共识类型,主要包括TDPoS、Pow、授权共识等,基于底层的共识安全能力。在这一层,用户可以定义有自己特色的共识类型,如类似TDPoS这种选举机制的共识,也可以定义Stakeing等的相关逻辑;
- 可插拔共识层:最上层是可插拔共识的运行态,包括Step Consensus 和Pluggable Consensus两个实例,该层主要负责维护了链从创建到当前高度的共识的所有升级历史。超级链的共识升级主要依赖系统的提案和投票机制,详情请查看 提案和投票机制文档
超级链共识主流程
超级链的是一个多链架构,其中单个链的主要逻辑在 core/xchaincore.go 文件中,其中与共识模块交互的函数主要有2个,分别是 Miner() 和 SendBlock() :
- Miner(): 这个函数的主要功能有2点,首先判断自己是否为当前的矿工,当判断自己是矿工时需要进行区块打包。
- SendBlock(): 这个函数是节点收到区块时的核心处理逻辑,当节点收到一个区块时会调用共识模块的相关接口进行区块有效性的验证,当验证通过后会将区块写入到账本中。
[img AD1713EC-B55D-4302-9346-D97FCF15061B]
超级链的共识整体流程如上图所示,主要包括7个步骤: - 用户提交交易到网络,交易执行完后会进入未确认状态,并记录在交易的未确认列表中TxPool中;
- 节点的Miner流程通过访问Consensus模块判断自己是否为当前的矿工;
- 当节点判断自己是矿工时需要从TxPool中拉取交易并进行区块的打包;
- 当矿工完成打包后会将区块广播给其他的验证节点,同时会通过步骤7将区块写入到账本;
- 如果某个时刻其他节点判断自己是矿工,同样地会按照上述1-5流程进行区块打包,打包完后会将区块广播给该节点;
- 节点收到区块后,会调用consensus模块进行区块的有效性验证;
- 矿工打包完后或者验证节点收到一个有效的区块后,将区块写入账本;
Chained-BFT共识公共组件
超级链底层有一个共识的公共组件叫chained-bft,其是Hotstuff算法的实现。HotStuff是一种简洁而优雅的bft改进算法。它具有以下优点: - 它的设计中将liveness和safty解耦开来,使得非常方便与其他的共识进行扩展;
- 将bft过程拆解成3阶段,每个阶段都是o(n)的通信;
- 它允许一个节点处于不同的view,并且将view的切换与区块结合起来,使得其能够实现异步共识,进一步提升共识的效率。
这样一个chained-bft可以在给定主集合的场景下确保网络的共识安全性,并且通过与外层共识配合工作实现共识的活性保证。
Xuperchain现有基于Chained-BFT的共识算法有:XPoA、XPoS
chained-BFT中区块需要在三个块后才被最终一致确认
HotStuff中明确了基本算法Basic HotStuff和链式算法Chained-HotStuff的概念,其中Chained-HotStuff是Basic HotStuff的流水线链式结构,也是超级链chained-BFT的算法原型。
和PBFT一样,Basic HotStuff也被分成了三个阶段: Prepare、Pre-Commit、Commit,如下图所示。
[img D2FB6839-164E-4389-9978-5869B5AF5EE2]
Chained-Hotstuff并发操作了原本的Basic HotStuff,将上一视图在所在阶段的信息发给下一视图的Leader,从而形成了流水线操作,增加效率。
正因为Basic HotStuff分为三个阶段,在完成三阶段的信息过程后,才最终形成一执行,即在当前视图在三个视图之后才最终完成了信息收集与执行。在chained-BFT中,视图与区块高度是一致绑定的,因此一个区块需要在三个区块后才被确认。
Smr
Smr是 chained-bft 的核心实例。他的主要的作用有以下几点: - 维护节点链的chained-bft共识状态机;
- 在外层共识的驱动下发起 NewView 和 NewProposal 等消息并更新本地状态;
- 处理其他验证节点的消息并更新本地状态;
[img D4CAB337-C876-4ACA-A556-5665E7097E18]
XPoS
简介
XPoS是超级链的一种改进型的DPoS算法,他是在一段预设的时间长度(一轮区块生产周期)内选择若干个验证节点,同时将这样一轮区块生产周期分为N个时间段, 这若干个候选节点按照约定的时间段协议协同挖矿的一种算法。在选定验证节点集合后,XPoS通过Chained-BFT算法来保证轮值期间的安全性。 总结一下,整个XPoS主要包括2大阶段: - 验证人选举:通过pos相关选举规则选出一个验证者集合;
- 验证人轮值:验证者集合按照约定的协议规则进行区块生产;
选举人选举
[img D5E42A9E-1B5C-4476-B426-B34B277BD933]
在XPoS中,网络中的节点有三种角色,分别是“普通选民”、“候选人”、“验证者”: - 选民:所有节点拥有选民的角色,可以对候选节点进行投票;
- 候选人:需要参与验证人竞选的节点通过注册机制成为候选人,通过注销机制退出验证人竞选;
- 验证人:每轮第一个节点进行检票,检票最高的topK候选人集合成为该轮的验证人,被选举出的每一轮区块生产周期的验证者集合,负责该轮区块的生产和验证,某个时间片内,会有一个矿工进行区块打包,其余的节点会对该区块进行验证。
网络中的三种角色之间是可以相互转换的,转换规则如下: - 所有地址都具有选民的特性,可以对候选人进行投票;
- 选民经过“候选人提名”提名接口成为候选人,参与竞选;
- 候选人经过“候选人退选”注销接口退出竞选;
- 候选人经过检票产出验证者,得票topK的候选人当选验证者;
- 验证者轮值完恢复候选人或者选民角色;
提名规则 - 节点想要参与竞选,需要先被提名为候选人,只有被提名的地址才能接受投票。为了收敛候选人集合,并一定程度上增加候选人参与的门槛,提名为候选人会有很多规则,主要有以下几点:
- 提名候选人需要冻结燃料,并且金额不小于系统总金额的十万分之一;
- 该燃料会被一直冻结,直到节点退出竞选;
- 提名支持自提和他提,即允许第三方节点对候选人进行提名;
- 被提名者需要知晓自己被提名,需要对提名交易进行背书;
选举规则
候选人被提名后,会形成一个候选人池子,投票需要针对该池子内部的节点进行。XPoS的投票也有很多规则,主要有以下几点: - 任何地址都可以进行投票,投票需要冻结燃料,投票的票数取决于共识配置中每一票的金额,票数 = 冻结金额 / 投票单价;
- 该燃料会被一直冻结,直到该投票被撤销;
- 投票采用博尔达计分法,支持一票多投,每一票最多投给设置的验证者个数,每一票中投给不同候选人的票数相同;
候选人轮值
每一轮开始的第一个区块会自动触发检票的交易,该交易会进行下一轮候选人的检票,被选举出的节点会按照既定的时间片协同出块,每一个区块都会请求所有验证节点的验证。XPoS的时间片切分如下图所示:
[img 924DD8B7-CB2C-419B-9E6D-8B5002028F55]
为了降低切主时容易造成分叉,XPoS将出块间隔分成了3个,如上图所示: - t1:同一轮内同一个矿工的出块间隔;
- t2:同一轮内切换矿工时的出块间隔,需要为t1的整数倍;
- t3:不同轮间切换时的出块间隔,需要为t1的整数倍;
XPoA共识
简介
XPoA是超级链对PoA的一种实现,其基本思想是在节点中动态设定一组验证节点,验证节点组在预设的时间段内进行组内轮流出块(称之为轮值),即其余节点在某特定验证节点V出块的时间段内统一将交易发送给V,交易由该验证节点V打包成区块。
XPoA支持动态变更验证节点,可以通过指令修改现有的验证节点组,包括对当前验证节点组进行删除和添加操作。在该算法中,预设时间段包括确定单个区块的出块时间,以及验证节点单次轮值出块数量。 同样,XPoA通过Chained-BFT算法来保证轮值期间的安全性。
技术细节
在XPoA中,网络中的节点有两种角色,分别是“普通节点”和“验证节点”: - 普通节点:普通节点仅对验证节点进行验证,计算当前时间点下验证节点地址是否于计算结果吻合。
- 验证节点:进行区块打包工作;在更改验证节点组过程中,多数验证节点需确定更改结果添加和删除操作方能生效。
修改验证组规则,验证组信息通过合约调用进行修改,流程主要有以下几点: - 在收到该信息后,验证节点通过签名信息确认交易真实性
- 验证节点在UtxoVM中进行系统调用并更新当前验证人集合读写集
- 验证人集合并不会立即影响当前共识,在三个区块后集合才能生效
验证节点间轮值:每一轮的时间由配置xuper.json指定,在单轮时间段内,区块打包由目前验证节点组中的节点按顺序轮流完成。在通过合约发起验证节点变更后,变更会在三个区块后才触发,然后验证节点按照新的验证组继续进行轮值。
[img AC93B41B-F3FA-4C37-9EC9-2E3C90A98A8C]
Single和PoW共识
介绍
Single以及PoW属于不同类型的区块链共识算法。其中,PoW(Proof Of Work,工作量证明)是通过解决一道特定的问题从而达成共识的区块链共识算法;而Single亦称为授权共识,在一个区块链网络中授权固定的address来记账本。Single一般在测试环境中使用,不适合大规模的应用环境。PoW适用于公有链应用场景。
只需修改 data/config 中的创世块配置即可指定使用共识
算法流程
Single共识 - 对于矿工:Single是固定 address 周期性出块,因此在调用 CompeteMaster 的时候主要判断当前时间与上一次出块时间间隔是否达到一个周期;
- 对于验证节点:验证节点除了密码学方面必要的验证之外,还会验证矿工与本地记录的矿工是否一致;
Pow共识 - 对于矿工:每次调用 CompeteMaster 都返回 true,表明每次调用 CompeteMaster 的结果都是矿工该出块了;
- 对于验证节点:验证节点除了密码学方面必要的验证之外,还会验证区块的难度值是否符合要求;
超级链监管机制
概述
超级链是一个具备政府监管能力的区块链系统。在设计上我们需要充分考虑监管和安全问题,做到安全可控。基于此我们超级链底层设计了一个监管合约的机制,通过该机制,超级链具备了对链上用户的实名、交易的安全检查等监管能力。
超级链在初始化时候,可以通过创世块配置的方式,配置这条链是否需要支持监管类型。对于配置了监管合约的链,这个链上所有的事务发起,无论是转账还是合约调用,系统会默认插入监管合约的执行,执行结果体现在读写集中,执行过程不消耗用户资源,执行结果所有节点可验证。
目前超级链支持的监管合约主要有以下几个: - 实名制合约: identity
- DApp封禁合约: banned
- 合规性检查合约: complianceCheck
- 交易封禁合约: forbidden
监管机制的使用 - 创世块的配置
创世块配置新增 reserved_contracts 配置,内容如下( 这个配置中配置了 identity 监管合约):
"reserved_contracts": [
{
"module_name": "wasm",
"contract_name": "identity",
"method_name": "verify",
"args":{}
}
]
- 编译实名合约
实名合约代码路径如下:core/contractsdk/cpp/reserved/identity.cc
实名合约实名的对象是一个具体的ak。
cd ./contractsdk/cpp
cp reserved/identity.cc example
./build.sh
编译好的产出为 ./build 文件夹下的identity.wasm文件。
2. 创建合约账户
在XuperChain中所有的合约都是部署在具体的某个账户下的,所以,为了部署实名合约,我们需要首先创建一个合约账户,注意,这里账户的拥有者可以修改其内合约Method的ACL权限管理策略,通过这种机制实现对谁可以添加实名状态和删除实名状态的控制。
./xchain-cli account new --account 1111111111111111
- 部署实名合约
部署合约需要消耗资源,所以先给上述合约账户转移一笔资源,然后在合约内部署上面的合约:
# 1 转移资源
./xchain-cli transfer --to XC 1111111111111111@xuper --amount 100000
# 2 部署实名合约 。 通过 -a 的creator参数,可以初始化被实名的ak。
./xchain-cli wasm deploy --account XC1111111111111111@xuper --cname identity -H localhost:37101 identity.wasm -a '{"creator":"addr1"}'
- 添加实名信息
合约调用json文件如下(合约名identity):
{
"module_name": "wasm",
"contract_name": "identity",
"method_name": "register_aks",
"args":{
"aks":"ak1,ak2"
}
}
具体步骤如下:
# 1: 生成原始交易
./xchain-cli multisig gen --desc identity_add.json --host localhost:37101 --fee 1000 --output tx_add.out
# 2: 本地签名
./xchain-cli multisig sign --output tx_add_my.sign --tx tx_add.out
# 3: 交易发送
./xchain-cli multisig send tx_add_my.sign --host localhost:37101 --tx tx_add.out
- 删除实名信息
合约调用json文件如下:
{
"module_name": "wasm",
"contract_name": "identity",
"method_name": "unregister_aks",
"args":{
"aks":"ak1,ak2"
}
}
具体步骤如下:
# 1: 生成原始交易
./xchain-cli multisig gen --desc identity_del.json --host localhost:37101 --fee 1000 --output tx_del.out
# 2: 本地签名
./xchain-cli multisig sign --output tx_del_my.sign --tx tx_del.out
# 3: 交易发送
./xchain-cli multisig send tx_del_my.sign tx_del_compliance_sign.out --host localhost:37101 --tx tx_del.out
- 实名信息验证
当用户向网络发起事务请求时,网络会验证交易中的 initiator 和 auth_require 字段是否都经过实名,如果都经过实名,则通过,否则,失败。
多盘散列
背景
区块链中的账本数据通常是只增不减,而单盘存储容量有上限。目前单盘最高容量是14TB左右,需要花费4000块钱;以太坊账本数据已经超过1TB,即使是在区块大小上精打细算的比特币账本也有0.5TB左右。区块链账本数据不断增加,单盘容量上限成为区块链持续发展的天花板。 目前对leveldb的多盘扩展方案,大部分是采用了多个leveldb实例的方式,也就是每个盘一个单独的leveldb实例。这种做法的好处是简单,不需要修改leveldb底层代码,缺点是牺牲了多行原子写入的功能。在区块链的应用场景中,我们是需要这种多个写入操作原子性的。所以选择了改leveldb底层模型的技术路线。
LevelDB数据模型分析
- Log文件:写Memtable前会先写Log文件,Log通过append的方式顺序写入。Log的存在使得机器宕机导致的内存数据丢失得以恢复;
- Manifest文件:Manifest文件中记录SST文件在不同Level的分布,单个SST文件的最大最小key,以及其他一些LevelDB需要的元信息;
- Current文件:LevelDB启动时的首要任务就是找到当前的Manifest,而Manifest可能有多个。Current文件简单的记录了当前Manifest的文件名;
以上3种文件可以称之为元数据文件,它们占用的存储空间通常是几十MB,最多不会超过1GB
SST文件:磁盘数据存储文件。分为Level 0到Level N多层,每一层包含多个SST文件;单个SST文件容量随层次增加成倍增长;文件内数据有序;其中Level0的SST文件由Immutable直接Dump产生,其他Level的SST文件由其上一层的文件和本层文件归并产生;SST文件在归并过程中顺序写生成,生成后仅可能在之后的归并中被删除,而不会有任何的修改操作。
[img 628222E0-0A59-431D-BB5A-648E7FCEE63F]
核心改造点
Leveldb的数据主要是存储在SST(Sorted String Table)文件中,写放大的产生就是由于compact的时候需要顺序读取Level-N中的sst文件,写出到Level-N+1的sst文件中。 我们将SST文件分散在多块盘上存储,具体的方法是根据sst的编号做取模散列,取模的底数是盘的个数, 理论上数据量和IO压力会均匀分散在多块盘上。
举个例子,假设某sst文件名是12345.ldb,而节点机器有3块盘用于存储(/disk1, /disk2, /disk3),那么就将改sst文件放置在 (12345 % 3) + 1, 也就是disk1盘上
[img AA0BA924-5DE0-4E73-8DC4-329D3B3C5A1A]
使用方式
leveldb.OpenFile 有两个参数,一个是db文件夹路径path,一个是打开参数Options; 如果要使用多盘存储,调用者需要设置 Options.DataPaths 参数,它是一个[]string 数组,声明了各个盘的文件夹路径。
扩容问题
假设本来是N块盘,扩容后是(N+M)块盘。对于已有的sst文件,因为取模的底数变了, 可能会出现按照原有的取模散列不命中的情况。 规则是: - 对于读Open,先按照 (N+M) 取模去Open,如果不存在,则遍历各盘直到能Open到相应的文件,由于Open并不是频繁操作,代价可接受,且SST的编号是唯一且递增的,所以不存在读取脏数据的问题;
- 对于写Open,就按照 (N+M) 取模,因为写Open一定是生成新的文件。
随着Compact的不断进行,整个数据文件的分布会越来越趋向于均匀分布在 (N+M) 个盘,扩容完成。
平行链与群组
背景
超级链具备平行链特性,能够实现业务的混部,确保整体架构性能上可以水平扩展;
同时,平行链还具备群组特性,能够一定程度上实现平行链隐私数据的隔离,只有群组内的节点才能有这个平行链的数据。 - 平行链 :相对于主链而言,运行在超级链中的用户级区块链实例,用户通过调用主链的智能合约创建。功能与主链无区别,全网节点均可以获取平行链账本数据,实现整体架构水平可扩展。
- 群组 :作用于平行链,具备群组特性的平行链,只有特定节点才拥有该平行链的账本数据。群组具备的特性包括私密性、动态性。
架构
平行链的群组特性通过白名单机制来实现,在网络层进行过滤。平行链的群组架构,如下图
[img 8503BA1E-8B15-45B3-97A1-A1D7F737A3A1]
设计思路
-
如果要支持群组,需要在xuper链部署一个系统合约:GroupChain(一个网络有且仅有一个)。这样是为了保证兼容性,如果没有部署这个GroupChain合约,那么行为和旧版本一致。<平行链名字,IP> → Address。为什么把IP放在Key中,是为了方便做过滤的时候查找更快,直接Get。平行链名字作为前缀,方便列出这条链的所有合法成员节点。备注:此处IP是代指一个TCP协议定位符,可以是libp2p风格的URL。
-
查询特定的链是否具备群组关系:Case1: 部分链希望有群组特性,即只有特定的节点才能同步账本数据;Case2: 剩下的链还是期望所有节点都参与同步、验证区块。基于以上两种场景,需要增加一层映射,即<平行链,是否支持群组>。如果每次转发都Lookup数据库过滤IP,性能有影响,可以考虑在p2p中维护一个Cache;
-
通过这个智能合约接口,可以修改(address, IP)的映射关系。合约的Owner(GroupChain这个合约的Owner)可以添加或删除address。节点也可以后期自己修改IP(节点有权更换自己的IP),合约里面会判断Initiator()字段和address是否一致,确保每个address只能修改自己的IP。
-
平行链中转消息的时候,必须确保目的IP在智能合约的映射表中存在。如果每次转发都Lookup数据库过滤IP,性能有影响,可以考虑在p2p中维护一个Cache;