一种锁定包含分片的区块链系统中跨片事务的方法及系统
技术领域
本说明书实施例属于区块链技术领域,尤其涉及一种锁定包含分片的区块链系统中跨片事务的方法及区块链系统、分片和节点。
背景技术
区块链(Blockchain)是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构,并以密码学方式保证的不可篡改和不可伪造的分布式账本。由于区块链具有去中心化、信息不可篡改、自治性等特性,区块链也受到人们越来越多的重视和应用。
发明内容
本说明书在于提供一种锁定包含分片的区块链系统中跨片事务的方法及区块链系统、分片和节点。
本说明书实施例提供的一种锁定包含分片的区块链系统中跨片事务的方法及区块链系统、分片和节点,通过以下方式实现:
一种锁定包含分片的区块链系统中跨片事务的方法,该区块链系统中至少包括两个分片,不同分片中的节点存储不同的状态集合;所述区块链系统还包括主链;
所述方法包括:
主链根据主链区块中的跨片交易涉及的目标分片将所述主链区块的区块体中跨分片交易需要目标分片执行的操作发送至对应的目标分片;
接收到所述主链区块的目标分片在生成分片区块的过程中,将接收到的需要由该目标分片执行的操作填入所述分片区块的区块体中。
一种锁定包含分片的区块链系统中跨片事务的区块链系统,该区块链系统中至少包括两个分片,不同分片中的节点存储不同的状态集合;所述区块链系统还包括主链;且,
主链根据主链区块中的跨片交易涉及的目标分片将所述主链区块的区块体中跨分片交易需要目标分片执行的操作发送至对应的目标分片;
接收到所述主链区块的目标分片在生成分片区块的过程中,将接收到的需要由该目标分片执行的操作填入所述分片区块的区块体中。
一种区块链主链,所述区块链主链是包含分片的区块链系统中的主链,所述分片用于存储状态的集合,且不同分片存储的状态的集合不同;
所述主链接收不同分片发来的跨片交易中需要由目标分片执行的操作;
所述主链生成主链区块的过程中,将需要由目标分片执行的操作填入所述主链区块的区块体中;
所述主链根据主链区块中的跨片交易涉及的目标分片将所述主链区块的区块体中跨分片交易需要目标分片执行的操作发送至对应的目标分片。
一种区块链分片,所述区块链分片是包含主链的区块链系统中的一个分片,用于存储状态的集合,且存储的状态的集合不同于其它分片中的状态的集合;
所述区块链分片接收主链发送的需要由所述区块链分片执行跨分片交易相关的操作;
所述区块链分片生成分片区块的过程中,将接收到的需要由该区块链分片执行的操作填入所述分片区块的区块体中。
一种区块链节点,所述区块链节点归属于区块链系统中的主链,所述区块链系统中包含分片,所述分片用于存储状态的集合,且不同分片存储的状态的集合不同;
所述区块链节点接收不同分片发来的跨片交易中需要由目标分片执行的操作;
所述区块链节点生成主链区块的过程中,将需要由目标分片执行的操作填入所述主链区块的区块体中;
所述区块链节点根据主链区块中的跨片交易涉及的目标分片将所述主链区块的区块体中跨分片交易需要目标分片执行的操作发送至对应的目标分片。
一种区块链节点,所述区块链节点归属于区块链系统中的一个分片,所述区块链分片是包含主链的区块链系统中的一个分片;区块链节点用于存储状态的集合,且存储的状态的集合不同于其它分片中节点存储的状态的集合;
所述区块链节点包括:
处理器;
存储器,其中存储有程序,其中在所述处理器执行所述程序时,执行如下内容:
所述区块链节点接收主链发送的需要由所述区块链分片执行跨分片交易相关的操作;
所述区块链节点生成分片区块的过程中,将接收到的需要由该区块链分片执行的操作填入所述分片区块的区块体中。
通过上述本申请的实施例,由于各个分片的区块体中填入了跨分片交易中涉及该分片的操作,这样,可以在当前分片中记录执行的跨分片交易的操作。
附图说明
为了更清楚地说明本说明书实施例的技术方案,下面将对实施例描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图仅仅是本说明书中记载的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动性的前提下,还可以根据这些附图获得其他的附图。
图1是一实施例中区块链系统架构示意图;
图2是一实施例中区块链系统分片架构的示意图;
图3是本说明书一实施例中的区块链数据存储的结构示意图;
图4是本说明书一实施例中的一个简化版的状态树示意图;
图5是本说明书一实施例中的一种区块链状态树的存储结构;
图6是本说明书一实施例中的一种区块链状态树的存储结构;
图7是本说明书一实施例中的一种区块链状态树的存储结构;
图8是本说明书一实施例中的一种区块链状态树的存储结构;
图9是本说明书一实施例中的一种区块链状态树的存储结构;
图10是本说明书一实施例中的一种区块链分片架构的示意图;
图11是本说明书一实施例中的一致性哈希的原理示意图;
图12是本说明书一实施例中的一种区块链状态树的存储结构;
图13是本说明书一实施例中的区块链节点示意图;
图14是本说明书一实施例中的区块链节点示意图;
图15是本说明书一实施例中的基于主链的区块链分片系统示意图;
图16是本说明书一实施例中的一种按照主链时钟表达主链和分片链生成区块的示意图;
图17是本说明书一实施例中的一种按照主链时钟表达主链和分片链生成区块的示意图;
图18是本说明书一实施例中的一种按照主链时钟表达主链和分片链生成区块的示意图;
图19是本说明书一实施例中的的主链和分片链之间消息机制的流程图。
具体实施方式
为了使本技术领域的人员更好地理解本说明书中的技术方案,下面将结合本说明书实施例中的附图,对本说明书实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本说明书一部分实施例,而不是全部的实施例。基于本说明书中的实施例,本领域普通技术人员在没有作出创造性劳动前提下所获得的所有其他实施例,都应当属于本说明书保护的范围。
目前限制区块链技术大规模落地应用的一个很重要因素是性能,即吞吐量,这个吞吐量一般可以通过每秒交易笔数(Transaction Per Second,TPS)来度量。开发者们提出了各种各样的方案来尝试提升区块的吞吐量,这一过程称为“扩容”。从扩容采用技术的方向上来说,可以分为链上扩容和链下扩容两个方向。链上扩容通常包括扩块、隔离见证、分片、共识层改进这些方案。链下扩容通常包括状态通道、侧链、链下计算这些方案。
分片技术是属于链上扩容的一种方案。分片概念源于数据库领域,本意是指数据库中数据的水平分区(将表的不同行分到不同的分区),每个分片都保存在一个单独的数据库服务器实例上,以分散负载。区块链分片的基本思路是将区块链网络中的节点分成若干个相对独立的子网络,每个子网络中包含一部分节点,一个子网络也就是一个分片(shard)。单个分片处理规模较小的事务,甚至只存储部分网络状态,多个分片并行处理事务,理论上整个网络的吞吐量将会提升。
分片技术根据不同的分片机制可以划分为三种:网络分片(network sharding),交易分片(transaction sharding),状态分片(state sharding)。网络分片是最基础的一种分片方式,就是将整个区块链网络划分成多个子网络,也就是多个分片。这样,区块链网络中的多个分片可以并行处理网络中不同的交易。交易分片是将交易按某种规则分配到不同分片,其思路为按一定规则将交易分配到同一个分片处理,这样既能够达到并行处理的目的又能避免双花问题。交易分片的前提是先进行网络分片。在所有的分片机制当中,状态分片是最具挑战的分片方式。状态分片的关键是将整个存储区分开,让不同的分片存储不同的部分,每个节点只负责存储自己的分片数据,而不是存储完整的区块链状态。状态分片能够解决存储能力瓶颈问题。
一些区块链系统架构如图1所示。如图1中,一个区块链系统例如包含A、B、C、D、E、F、G、H、I、J、K、L、M、N、O、P共16个全量节点。节点之间的连线示意性的表示P2P(Peer toPeer,点对点)连接。这些节点上都存储全量的账本,即承担着存储全部交易、智能合约和各种状态。随着区块链业务的增长,单个节点存储的数据量也会越来越大,有的达到T数量级(1TB=1024GB),甚至到达P或E的数量级(1PB=1024TB,1EB=1024PB)。为了支撑区块链系统的运行和应对业务的持续,对于每一个节点都需要寻求扩容(获得更大的存储空间)而进行巨大的花费。
基于此,本说明书实施例提供了一种区块链系统。区块链系统中的节点进行分片后例如如图2所示,分为4个分片。每个分片包括4个节点。每个分片内的节点之间的连线表示P2P连接,每个分片之间的连线也表示P2P连接。本实施例仅仅是为了便于举例而示意性的列举4个分片,每个分片包括4个节点。实际上,每个分片中节点的数量可以不同。此外,部分或者全部分片之间可能没有网络连接,也就是说,在一些情况下,部分或者全部分片之间可能并不直接通信。为了支持分片之间的通信,区块链网络中可以包括一个为所有分片提供服务的主链。这个主链在图2中并没有显示出。
为了说明本申请中的状态分片方法,先介绍本申请涉及的区块链状态存储结构。鉴于很多区块链平台和应用是基于以太坊(Ethereum)的底层技术而构建的,这里先介绍以太坊的状态存储结构。当然,基于其他区块链技术构建的区块链系统,也可能适用于本申请的核心内容,例如基于Fabric的超级账本(Hyperledger)和企业操作系统(EnterpriseOperating System,EOS)、Quorum、Corda等,不再赘述。
以太坊相比于比特币网络进行了拓展,采用账户系统和世界状态,可以直接用账户来显示的记录账户的余额和状态。以太坊的账户可以分为两种类型:
外部账户(Externally owned account):用户的账户,例如以太币拥有者账户。
合约账户(contract account):存储执行的智能合约代码以及智能合约代码中状态的值,通常只能通过外部账户调用激活。
外部账户和合约账户的设计,实际上是账户地址到账户状态的映射。账户的状态通常包括 nonce、balance、storage_Root、codeHash 等字段。nonce、balance在外部账户和合约账户中都存在。codeHash和storage_Root属性一般仅在合约账户上有效。
nonce:计数器。对于外部账户,这个数字代表从账户地址发送的交易数量;对于合约账户,是账户创建的合约数量。
balance:这个地址拥有的以太币的数量。
storage_Root :一个MPT树根节点的哈希,这个MPT树对合约账户的状态变量的存储进行组织。
codeHash:智能合约代码的哈希值。对于合约账户,这是智能合约被哈希计算并存储的代码;对于外部账户,由于不包括智能合约,因此codeHash字段一般可以是空字符串/全0字符串。
MPT全称为Merkle Patricia Tree,是结合了Merkle Tree(默克尔树)和PatriciaTree(压缩前缀树,一种更节省空间的Trie树,字典树)的一种树形结构。Merkle Tree,默克尔树算法对每个交易都计算一个Hash值,然后两两连接再次计算Hash,一直到最顶层的Merkle根。以太坊中采用改进的MPT树,例如是16叉树的结构,通常也简称为MPT树。
以太坊MPT树的数据结构包括状态树(state trie)。状态树中包含以太坊网络中每个账户所对应的存储内容的键值对(key and value pair)。状态树中的“键”可以是一个的160bits标识符(以太坊账户的地址),这个账户地址分布于从状态树的根节点开始到叶子节点的存储中。状态树中的“值”是通过对以太坊账户的信息进行编码(使用递归长度字典编码(Recursive-Length Prefix encoding,RLP)方法)生成的。如前所述,对于外部账户来说,值包括nonce和balance;对于合约账户来说,值包括nonce、balance、codehash和storage_Root。
合约账户用于存储智能合约相关的状态。智能合约在区块链上完成部署后,会产生一个对应的合约账户。这个合约账户一般会具有一些状态,这些状态由智能合约中状态变量所定义并在智能合约创建、执行时产生新的值。所述的智能合约通常是指在区块链环境中以数字形式定义的能够自动执行条款的合约。一旦某个事件触发合约中的条款(满足执行条件),代码即可以自动执行。在区块链中,合约的相关状态保存在存储树(storagetrie)中,存储树根节点的hash值即存储于上述storage_Root中,从而将该合约的所有状态通过hash锁定到该合约账户下。存储树也是一个MPT树形结构,存储了状态地址到状态值的key-value映射。从存储树的根节点到叶子节点存储有一个状态的地址,一个叶子节点中存储一个状态的值。
图3是一个区块链数据存储的结构示意图。由图3所示的一些的区块链数据存储中,每一区块的区块头包括若干字段,例如上一区块哈希previous_Hash(图中的PrevHash,或称为父hash),随机数Nonce(在一些区块链系统中这个Nonce不是随机数,或者在一些区块链系统中不启用区块头中的Nonce),时间戳Timestamp,区块号BlockNum,状态根哈希State_Root,交易根哈希Transaction_Root,收据根哈希Receipt_Root等。其中,下一区块(如区块N+1)的区块头中的PrevHash指向上一区块(如区块N),即为上一区块的hash值。通过这种方式,区块链上通过区块头实现了下一区块对上一区块的锁定。特别的,如前所述,state_root是当前区块中所有账户的状态组成的MPT树的根的哈希值,即指向state_root的为一棵MPT形式的状态树。这个MPT树的根节点可以为一个扩展节点(Extension Node)或一个分支节点(Branch Node),state_root中存储的一般为这个根节点的hash值。从这个MPT的根节点到叶子节点中每个节点的一部分值按照顺序串联起来可以构成账户地址并作为key,叶子节点中存储的账户信息为这个账户地址对应的value,这样,构成了key-value键值对。具体的,这个key可以是sha3(Address), 即账户地址的hash值(hash算法例如采用sha3算法),其存储的值value可以为rlp(Account),即账户信息的rlp编码。其中账户信息是[nonce,balance,storage_Root,codeHash]构成的四元组。如前所述,对于外部账户来说,一般只有nonce和balance两项,而storage_Root、codeHash字段默认存储空字符串/全0字符串。也就是说,外部账户不存储合约,也不存储合约执行后的产生的状态变量。合约账户一般包括nonce, balance, storage_Root, codeHash。其中nonce是该合约账户的交易计数器;balance是账户余额;storage_Root对应另外一个MPT,通过storage_Root能链接到合约相关的状态的信息;codeHash是合约代码的hash值。不论是外部账户还是合约账户,其账户信息一般都位于一个单独的叶子节点(Leaf Node)中。从根节点的扩展节点/分支节点到每个账户的叶子节点,可能中间会经过若干个分支节点以及扩展节点。
状态树可以是MPT形式的树,一般是16叉树,每一层最多可以有16个孩子节点,而最多可以有64层的深度。对于扩展节点,用于存储共同前缀,其一般有1个孩子节点,这个孩子节点可以是分支节点。对于分支节点,其最多可以有16个孩子节点,其中可能包括扩展节点和/或叶子节点。这样的MPT树最多可以有64层的深度。当区块链中的账户数量达到一定数量时,这棵MPT树可能接近或达到64层的深度。
其中,对于状态树中的一个合约账户来说,其storage_Root指向另一棵同为MPT形式的树,其中存储了合约执行涉及的状态变量(state variable)的数据。这个storage_Root指向的MPT形式的树为存储树,即存储树的根节点的hash值。一般的,这个存储树存储的也是key-value键值对。从根节点到叶子节点的路径上存储的一部分数据连起来构成key,叶子节点中存储value。前面提到,这个存储树也可以是MPT形式的树,一般也是16叉树,即对于分支节点,其最多可以有16个孩子节点,其中可能包括扩展节点和/或叶子节点。而对于扩展节点,其一般可以有1个孩子节点,其可以是分支节点。这棵存储树最多可以有64层的深度。
智能合约中,例如通过以太坊提供的solidity高级开发语言中,可以定义的状态变量包括两种类型,一种是基本数据类型的状态变量,另一种是映射(map或mapping)类型的状态变量。以下是一个用solidity编写的智能合约的代码的片段:
contract Demo {
int a;
int x;
mapping(address => int) public balanceA;
function myfunc() public {
a = 8;
x = 9;
balanceA [123] = 100;
}
}
其中,整形变量a、x都属于基本数据类型,在myfunc函数中,a赋值为8,x赋值为9。映射类型数据结构中,上面代码中定义了外部账户地址到一种资产类型的余额(balanceA,不同于外部账户中的balance和合约账户中的balance)的映射,即地址address→balanceA的映射。在myfunc函数中,例如为外部账户的地址123初始化对应的balanceA为100。
以太坊和其它区块链系统中,例如可以在智能合约中按照ERC20标准创建新的数字资产,当然也可以是按照其他方式自定义的数字资产。例如上述的balanceA即可以为按照ERC20标准创建的一种数字资产。当然,在一个智能合约中,可以定义多个资产类型,例如balanceA、balanceB、balanceC、…。这个合约中的映射可以为每个外部账户赋予持有和交易这种新创建的数字资产的能力。如上述代码的例子,一般的,每个外部账户都可以对应一个balanceA类型的资产。那么,如果区块链的状态树中存在10000个外部账户,则通过智能合约,每个外部账户可以对应持有/交易balanceA类型的资产,即存在10000个“外部账户→balanceA”的映射。
需要说明的是,这里的资产是广义的,还可以是余额外的其它内容。例如在区块链电子发票的场景中,资产可以定义为发票的代码集合,这个集合例如为balanceP。这样,在“外部账户→balanceP”的映射中,balanceP中可以包括一组发票的代码集合。这个发票代码集合中可能会增加新的发票代码。
上述的基本数据类型和映射类型的状态变量,在存储树中都可以是以key-value键值对的形式存储。对于基本数据类型,key是合约中的状态变量声明的位置(从0开始计数)。对于映射类型,key = SHA3(映射中的关键字,变量声明位置),也就是把映射中的关键字和状态变量声明位置拼在一起成为一定长度(例如64字节)的字符串后计算hash值。value可以存储状态变量的实际值。
前面提到,如果区块链的状态树中存在10000个外部账户,则通过智能合约,每个外部账户可以对应持有/交易balanceA类型的资产,即存在10000个外部账户→balanceA的映射。具体的,该合约账户下,存储树中可以存储这些映射的值。如上所述,具体是通过key-value的方式存储在存储树中。类似的,这个存储树也可以是MPT形式的树,一般也是16叉树,每一层最多可以有16个孩子节点,最多可以有64层的深度。从这个MPT的根节点到叶子节点中存储的一部分数据连起来可以作为key,叶子节点中存储的信息为这个key对应的value。这样,就构成了key-value键值对。
当区块链中的外部账户的数量达到一定量时,状态树的深度可能接近或达到64层的深度。类似的,合约中映射类型的状态变量的数量也可能达到相同的量,这时存储树也接近或达到64层的深度。此外,对于一个智能合约来说,合约中基本数据类型的变量不会太多,一般不会超过32个。这样,当外部账户的数量较大时,加上合约中基本数据类型的变量,合约中的状态变量的总数与外部账户基本是差不多的。
图4是一个简化版的状态树示意图。区块链系统中存在若干外部账户,例如图4中分别编号的外部账户 1、外部账户 2,…。此外,区块链系统中存在若干合约账户,例如图4中的分别编号的合约账户 1,合约账户 2,…。这些外部账户和合约账户及其信息内容例如通过MPT树的形式组织,构成状态树。区块头中的state_root存储这个MPT树的根节点的hash值。图4中以节点1、节点2、节点3共三个节点来示意性的表示MPT树的形式,具体的,可以表示MPT树中的扩展节点、分支节点。
外部账户可以通过创建合约的交易在区块链上部署智能合约。此外,智能合约也可以是原生合约,即融合在区块链平台的代码中,与区块链平台代码一同编译后完成部署。不论是哪种形式部署的智能合约,在合约创建后,区块链上出现一个与该智能合约对应的合约账户,并拥有一个特定的地址,合约代码和账户存储将保存在该合约账户中。智能合约的账户存储保存了这个合约的状态。合约创建之后,外部账户可以调用创建的智能合约,也可以是外部账户通过智能合约来调用智能合约(也可以通过1个或多个智能合约来调用智能合约)。被调用的智能合约,将产生的状态变量以key-value的形式写入该智能合约的账户存储中,如图4所示。这些key-value,可以组织成MPT树的形式,构成存储树。存储树中,key-value除了包括基本数据类型的状态变量外,还可以包括映射类型的状态变量。一般的,一个合约中不超过32个基本类型的状态变量,即一般一个存储树中包括不超过32个key-value来对应基本类型的状态变量的存储。一个合约中,映射类型的状态变量一般与外部账户对应。存在N个外部账户的情况下,一个合约中一般存在对应的N个key-value来对应映射类型的状态变量的存储。
合约账户中的映射类型的状态变量的数量一般与外部账户对应,此外,合约账户中还包括基本类型的状态变量。当外部账户的数量比较多时,合约账户中的映射类型的状态变量的数量也很多。状态树实际上包括了两层MPT结构,每一层最大深度是64层。对于区块链系统中大量的合约操作,都要涉及合约的状态变量。这样,在现有的账户体系结构中,虽然建立了外部账户和合约账户,但是操作的热点将集中于合约账户中的状态变量,而关于外部账户的操作却很少。这就形成了单账户热点。单账户热点导致合约账户存储的负载压力比较大,将限制和影响区块链系统的性能。
本说明书实施例提供一种区块链状态树的存储结构。如图5所示。
区块头中的state_root存储整个状态树的根节点的hash值。树形结构例如可以采用图3中的MPT,当然也可以采用其他组织形式,这一点以下类似,以MPT为例进行说明。整体上,状态树可以采用三层树形结构。例如对于MPT来说,图5中每一层以节点1、节点2、节点3共三个节点来示意性的表示MPT树的形式,具体的,可以表示MPT树中的扩展节点、分支节点。第一层树形结构的叶子节点可以用来存储外部账户存储的根hash值,此外还可以存储合约账户的一些基本信息。外部账户和合约账户可以分别有若干个。一般的区块链应用场景中,外部账户的数量可能明显多于合约账户的数量。第一层叶子节点中每个外部账户的账户信息的根hash,可以基于包括该外部账户的nonce、balance以及该外部账户涉及的智能合约存储的hash值计算得到。其中,图5中外部账户的nonce、balance可以与图3、图4中相同。第二层为合约存储树(schematic storage trie)。具体的,第二层树形结构的根节点为外部账户涉及的智能合约的存储的hash值。类似的,第二层可以通过一个以节点1、节点2、节点3共三个节点来示意性的表示MPT树的形式,具体的,可以表示MPT树中的扩展节点、分支节点。第二层的存储可以包括一个或多个智能合约,即可以有多个叶子节点。第二层的每个叶子节点可以用来存储该外部账户下涉及的一个智能合约的存储的根hash值,可以基于包括该外部账户涉及的合约ID(contractID)、storage_root计算得到。第三层为存储树。具体的,第三层树形结构的根节点为外部账户涉及的智能合约中的状态变量的根hash值。类似的,第三层可以通过一个以节点1、节点2、节点3共三个节点来示意性的表示MPT树的形式,具体的,可以表示MPT树中的扩展节点、分支节点。第三层的每个叶子节点可以用来存储合约中的一个状态变量的value值。上述的三层树的结构,每棵树的根节点到叶子节点的路径上存储的一部分数据连起来可以构成key,叶子节点中可以存储value。这样,通过这样的存储模型,可以在每个外部账户下存储该外部账户涉及的每个智能合约中的状态变量的key-value。
本说明书实施例提供一种区块链状态树的存储结构。如图6所示。
实际的区块链商业系统中,很多情况下一个区块链专注于提供一种服务。一种服务一般可以采用一个智能合约来实现。这种情况下,该区块链系统中只有一个智能合约。在只有一个智能合约时,图5中的第二层可以得到简化,不需要图5中的第二层结构,则如图6所示。第一层树形结构的叶子节点中每个外部账户的根hash,可以基于包括该外部账户的nonce、balance以及该外部账户涉及的智能合约存储的hash值计算得到。其中,图6中外部账户的nonce、balance可以与图3、图4中相同。第二层为存储树。具体的,第二层树形结构的根节点为外部账户涉及的智能合约中的状态变量的根hash值。类似的,第二层可以通过一个以节点1、节点2、节点3共三个节点来示意性的表示MPT树的形式,具体的,可以表示MPT树中的扩展节点、分支节点。第二层的每个叶子节点可以用来存储合约中的一个状态变量的value值。上述的两层树的结构,每棵树的根节点到叶子节点的路径上存储的一部分数据连起来可以构成key,叶子节点中可以存储value。这样,通过这样的存储模型,可以在每个外部账户下存储该外部账户涉及的每个智能合约中的状态变量的key-value。
图3、图4的合约账户存储中包括了该合约涉及的所有状态变量。通过本申请上述图5、图6实施例提供区块链状态树的存储结构,实际上将原有的合约账户存储中涉及的该合约中所有状态变量按照关联的外部账户,分解到了对应的外部账户的存储中。例如,原有的合约账户存储中包括了该合约涉及的所有映射类型的状态变量1、2、3、…10000,其中1-1000与外部账户1相关,1001-2000与外部账户2相关,以此类推。这样,将与外部账户1相关的映射类型的状态变量1-1000,分解到了外部账户1的存储中;将与外部账户2相关的映射类型的状态变量1001-2000,分解到了外部账户2的存储中,以此类推。
除了映射数据结构,还可以通过其它数据结构定义外部账户地址到一种资产类型的映射,这里并不限制。
最简单的情形例如图7所示,一个区块链系统中创建了一个智能合约,而且该智能合约中定义了一种新类型的资产。而且,创建的合约中,可以仅定义一种新类型的资产,或者是定义多种新类型资产的情况下仅启用其中的一种(而另外的新类型资产未启用或未初始化)。这种情况下,由于每个外部账户对应一种类型的资产的余额,所以该类型的资产的余额可以不需要组织成树的形式,通过一个key-value即可以存储。其中,这个映射类型中,key = SHA3(映射中的关键字,变量声明位置),也就是把映射中的关键字和状态变量声明位置拼在一起成为一定长度(例如64字节)的字符串后计算hash值。value可以存储变量的实际值,即balanceA类型的资产的余额。这样,外部账户的storage_root可以是这个key-value的hash值。每个外部账户都可以有一个这样的映射数据。例如,外部账户1的storage_root指向其映射类型中一个key-value;外部账户2指向其映射类型中一个key-value;以此类推。综上,对于区块链系统中仅有一个智能合约的情况,且该智能合约中仅定义或启用了一种新类型的资产,则区块链中的状态树的存储包括两层;第一层通过树形结构在每个叶子节点中存储一个外部账户相关的包括所述新类型资产的key-value的hash值;第二层存储所述映射定义的包括所述外部账号与所述新类型资产的key-value形式的映射关系。
前面提到,在一个智能合约中,可以定义多个资产类型,例如balanceA、balanceB、balanceC、balanceD、…。这样,每个外部账户可以有分别对应balanceA、balanceB、balanceC、balanceD、…类型的资产的余额。这种情况下,由于每个外部账户对应多种类型的资产的余额,该多种类型的资产的余额可以组织成树的形式。如图6中所示,在第二层的存储树中,通过节点1、节点2、节点3共三个节点来示意性的表示一种树的形式。这个树例如是MPT树,则节点1、节点2、节点3可以示意性的表示MPT树中的扩展节点、分支节点。其中,这个映射类型中,key = SHA3(映射中的关键字,变量声明位置),也就是把映射中的关键字和状态变量声明位置拼在一起成为一定长度(例如64字节)的字符串后计算hash值。value可以存储状态变量的实际值,即balanceA、balanceB、balanceC、balanceD、…类型的资产的余额。如图4中,外部账户1的存储树的叶子节点分别具有balanceA、balanceB、balanceC、balanceD、…类型的资产的余额。这样,外部账户的storage_root可以是balanceA、balanceB、balanceC、balanceD、…类型的资产的key-value组成树的形式后的根hash值。每个外部账户都可以有一个这样的映射数据。例如,外部账户1的storage_root指向其映射类型中一组key-value的树形结构;外部账户2的storage_root指向其映射类型中一组key-value的树形结构。以此类推。这样,对于区块链系统中仅有一个智能合约的情况,且该智能合约中定义且启用了至少两种新类型的资产,则区块链中状态树的存储包括两层;第一层通过树形结构在每个叶子节点中存储一个外部账户相关的包括所有所述新类型资产的key-value的根hash值;第二层通过树形结构在每个叶子节点中存储所述映射定义的包括所述外部账号与一种所述新类型资产的key-value形式的映射关系。
在一个区块链系统中,可以创建多个智能合约。例如一个区块链系统中创建了多个智能合约,这些智能合约可以通过树形结构组织起来,如图8所示,即如图中的第二层为合约存储树。大多数智能合约中的每个,可以定义一种或多种新类型的资产。每个智能合约中,有不同的状态。例如图8中,通过树形结构连接外部账户1的,示出了两个合约。每个合约基于其ID、storage_root可以计算得到一个hash值,该hash值可以存储于第二层树形结构的一个叶子节点中,如图中的schematic_storage_root中。对于这两个创建的合约中的每个仅定义一种新类型的资产的情况,或者是定义多种新类型资产的情况下仅启用其中的一种(而另外的新类型资产未启用或未初始化)的情况,每个合约对应一种类型的资产的余额,所以该类型的资产的余额可以不需要组织成树的形式,通过一个key-value即可以存储,类似图7中的第二层结构。这样,一个智能合约的storage_root可以是这个key-value的hash值。以此类推。综上,对于区块链系统中有至少两个智能合约的情况,且该智能合约中仅定义或启用了一种新类型的资产,则区块链中状态树的存储包括三层;第一层通过树形结构在每个叶子节点中存储与一个外部账户相关的包括所有智能合约涉及信息的根hash值;第二层通过树形结构在每个叶子节点中存储一个外部账户相关的包括一个智能合约涉及的所述新类型资产的key-value的hash值;第三层存储所述映射定义的包括所述外部账号与所述资产的key-value形式的映射关系。
在一个区块链系统中,可以创建多个智能合约,并且每个合约中可以定义多个资产类型,例如balanceA、balanceB、balanceC、balanceD、…。该情况可以如图5所示。通过树形结构连接外部账户1的,示出了两个合约。即为第二层合约存储树。实际上,第二层的存储可以包括多个智能合约,即可以有多个叶子节点。每个合约基于其ID、storage_root可以计算得到一个hash值,该hash值可以存储于第二层树形结构的一个叶子节点中,如图中的schematic_storage_root中。第二层的每个叶子节点可以用来存储该外部账户下涉及的一个智能合约的存储的根hash值,可以基于包括该外部账户涉及的合约ID(contract ID)、storage的hash值计算得到。第三层为存储树。具体的,第三层树形结构的根节点为外部账户涉及的智能合约中的状态变量的根hash值。类似的,第三层可以通过以节点1、节点2、节点3共三个节点来示意性的表示MPT树的形式,具体的,可以表示MPT树中的扩展节点、分支节点。第三层的每个叶子节点可以用来存储合约中的一个状态变量的value值。上述的三层树的结构,每棵树的根节点到叶子节点的路径上存储的一部分数据连起来可以构成key,叶子节点中可以存储value。这样,通过这样的存储模型,可以在每个外部账户下存储该外部账户涉及的每个智能合约中的状态变量的key-value。综上,对于区块链系统中有至少两个智能合约的情况,且该智能合约中仅定义或启用了至少两种新类型的资产,则区块链中状态树的存储包括三层;第一层通过树形结构在每个叶子节点中存储与一个外部账户相关的包括所有智能合约涉及信息的根hash值;第二层通过树形结构在每个叶子节点中存储一个外部账户相关的包括一个智能合约涉及的所有所述新类型资产的key-value的根hash值;第三层通过树形结构在每个叶子节点存储所述映射定义的包括所述外部账号与一种所述新类型资产的key-value形式的映射关系。
上述图5-8的示例中,所述第一层通过树形结构在每个叶子节点中还可以存储该外部账户的交易计数。
上述图5、图8的示例中,显示出所述第二层通过树形结构在每个叶子节点中还存储关联的智能合约的编号的情形。此外,所述第二层还可以不在每个叶子节点中存储关联的智能合约的编号,而是第二层的根节点通过第二层的树形结构到第二层每个叶子节点的路径中存储涉及的智能合约的地址或基于所述涉及的智能合约的地址的映射值。
结合上述内容,本申请一种区块链系统中的状态存储方法,如图9所示。该区块链系统中至少包括两个分片,而且,不同分片中的节点存储不同的外部账户集合的状态。
所述区块链系统,可以如图10所示,例如包括4个分片。每个分片可以包括4个节点。每个分片中的4个节点可以都是全量节点。这仅是一个说明性是的实例,也可以不同的分片具有不同数量的节点,这里并不限定。每个分片中包含的节点可以满足拜占庭容错(Byzantine Fault Tolerance,BFT)要求。所述的拜占庭容错要求可以理解为在分片内部可以存在拜占庭节点,而分片对外不体现拜占庭行为。一般的,一些拜占庭容错算法中要求节点个数大于3f+1,f为拜占庭节点个数,例如实用拜占庭容错算法PBFT(PracticalByzantine Fault Tolerance)。
不同分片中的节点可以存储不同的外部账户集合的状态。如图10中的举例,分片1中的节点A、B、C、D,每个节点的状态存储外部账户1、5、9、13...(例如按照从1起始间隔为4的正整数标明的外部账户构成的集合)的状态。关于外部账户1、5、9、13...的状态在节点A、B、C、D中的存储方式,如图5-8中的任一示例。
以结合最简单的图7中的实现为例,区块链系统中创建了一个智能合约,而且该智能合约中定义了一种新类型的资产。创建的合约中可以仅定义一种新类型的资产,或者是定义多种新类型资产的情况下仅启用其中的一种(而另外的新类型资产未启用或未初始化)。这种情况下,由于每个外部账户对应一种类型的资产的余额,所以该类型的资产的余额可以不需要组织成树的形式,通过一个key-value即可以存储。其中,这个映射类型中,key = SHA3(映射中的关键字,变量声明位置),也就是把映射中的关键字和变量声明位置拼在一起成为一定长度(例如64字节)的字符串后计算hash值。value可以存储变量的实际值,即balanceA类型的资产的余额。这样,外部账户的storage_root可以是这个key-value的hash值。每个外部账户都可以有一个这样的映射数据。例如,外部账户1的storage_root指向其映射类型中一个key-value;外部账户2指向其映射类型中一个key-value;以此类推。综上,对于区块链系统中仅有一个智能合约的情况,且该智能合约中仅定义或启用了一种新类型的资产,则区块链中的状态树的存储包括两层;第一层通过树形结构在每个叶子节点中存储一个外部账户相关的包括所述新类型资产的key-value的hash值;第二层存储所述映射定义的包括所述外部账号与所述新类型资产的key-value形式的映射关系。
以结合图6中的实现为例,在一个智能合约中,可以定义多个资产类型,例如balanceA、balanceB、balanceC、balanceD、…。这样,每个外部账户可以有分别对应balanceA、balanceB、balanceC、balanceD、…类型的资产的余额。这种情况下,由于每个外部账户对应多种类型的资产的余额,该多种类型的资产的余额可以组织成树的形式。这样,对于区块链系统中仅有一个智能合约的情况,且该智能合约中定义且启用了至少两种新类型的资产,则区块链中状态树的存储包括两层;第一层通过树形结构在每个叶子节点中存储一个外部账户相关的包括所有所述新类型资产的key-value的根hash值;第二层通过树形结构在每个叶子节点中存储所述映射定义的包括所述外部账号与一种所述新类型资产的key-value形式的映射关系。
以结合图8中的实现为例,一个区块链系统中创建了多个智能合约,这些智能合约可以通过树形结构组织起来,即如图8中的第二层为合约存储树。对于这两个创建的合约中的每个仅定义一种新类型的资产的情况,或者是定义多种新类型资产的情况下仅启用其中的一种(而另外的新类型资产未启用或未初始化)的情况,每个合约对应一种类型的资产的余额。这样,对于区块链系统中有至少两个智能合约的情况,且该智能合约中仅定义或启用了一种新类型的资产,则区块链中状态树的存储包括三层;第一层通过树形结构在每个叶子节点中存储与一个外部账户相关的包括所有智能合约涉及信息的根hash值;第二层通过树形结构在每个叶子节点中存储一个外部账户相关的包括一个智能合约涉及的所述新类型资产的key-value的hash值;第三层存储所述映射定义的包括所述外部账号与所述资产的key-value形式的映射关系。
以结合图5中的实现为例,一个区块链系统可以创建多个智能合约,并且每个合约中可以定义多个资产类型。这样,对于区块链系统中有至少两个智能合约的情况,且该智能合约中仅定义或启用了至少两种新类型的资产,则区块链中状态树的存储包括三层;第一层通过树形结构在每个叶子节点中存储与一个外部账户相关的包括所有智能合约涉及信息的根hash值;第二层通过树形结构在每个叶子节点中存储一个外部账户相关的包括一个智能合约涉及的所有所述新类型资产的key-value的根hash值;第三层通过树形结构在每个叶子节点存储所述映射定义的包括所述外部账号与一种所述新类型资产的key-value形式的映射关系。
不同分片中的节点可以存储不同的外部账户集合的状态。除了如图10中对分片1的举例,分片2中的节点E、F、G、H,每个节点的状态存储外部账户2、6、10、14...(例如按照从2起始间隔为4的正整数标明的外部账户构成的集合)的状态;分片3中的节点I、J、K、L,每个节点的状态存储外部账户3、7、11、15...(例如按照从3起始间隔为4的正整数标明的外部账户构成的集合)的状态;分片4中的节点M、N、O、P,每个节点的状态存储外部账户4、8、12、16...(例如按照从4起始间隔为4的正整数标明的外部账户构成的集合)的状态。分片2、3、4中的节点存储对应外部账户的方式,与上述类似,这里了不再赘述。需要说明的是,不同分片对应的不同外部账户集合,这些集合之间可以有一定的交集。例如,分片2和分片3分别对应的两个外部账户集合和,两个集合之间可以没有交集的外部账户,也可以有一定交集的外部账户。
上面图10的例子中,不同分片对应的外部账户,根据外部账户的唯一标识分别从不同的初始值开始以相同的间隔构成的账户集合,这是一种取模的方式。除了这种取模的方式外,还可以采用分段的方式。例如,区块链系统中的外部账户包括ID为1-4000的共4000个账户。可以分配分片1中的节点存储外部账户1-1000的状态,分片2中的节点存储外部账户1001-2000的状态,分片3中的节点存储外部账户2001-3000的状态,分片4中的节点存储外部账户3001-4000的状态。上述的取模或者分段,可以是针对外部账户的ID划分,也可以是针对外部账户的地址划分,或者针对ID或地址的hash值划分,等等,整体上根据账户的某个唯一标识划分即可,这里并不限制。
这样,当区块链系统中产生新的注册用户时,可以根据该用户的诸如ID、地址、ID/地址的hash值确定该用户的外部账户的状态,包括执行合约所产生的与该外部账户相关的状态(如前述提到的映射类型的key-value),相对固定的存储于某个分片的节点存储中。
如果仅仅按照取模或者分段的方式,当需要增加或者减少分片时,都有可能会改变大多数账户存储与分片的映射关系,这样显然是不经济的,而且长时间的调整可能会造成大量与账户存储有关的操作的无法命中正确的分片及节点。
正是考虑到这一点,除了上述取模、分段的方式外,还可以采用一致性哈希的方式将账户的状态存储分配至相应的分片上。这种方式中,可以将分片shard映射到数值空间[0, 2^32 - 1],映射规则可以是分片的标识之类,例如通过某种hash算法来进行映射。并且,可以将账户也映射到该数值空间[0, 2^32 - 1],映射规则可以是账户的地址、注册地之类,例如通过同样的hash算法来进行映射。对于某个账户account,如果满足hash(shard)<= hash(account) 的节点,选择 hash(shard) 最大的节点存放这个account。如果没有满足上述条件的shard,选择 hash(shard) 最小的shard存放该account,如图11中的示意。可以简单的解释为根据账户account的hash值将对应的状态分配至图11中的环的顺时针方向的第一个分片哈希值对应的分片中。采用一致性哈希方式进行分配,当分片发生变化时,仅有较少部分的外部账户相关的存储会发生变化,不至于使大多数的分片的存储进行调整,从而降低=命中低的问题。
此外,还可以根据账户注册地将账户的状态存储分配至相应的分片上。所述的注册地可以包括用户注册账户时所连接的区块链节点,例如,用户注册账户时通过客户端连接至区块链节点E,节点E属于分片2,则注册生成的账户对应于分片2。另一些实施场景中,所述的注册地也可以为用户注册账户时所在的地理位置。例如一个用户在注册账户时其IP地址位于香港特别行政区,而区块链系统中有一个分片对应于相关特别行政区的区块链业务,例如分片4,则该用户注册的账户对应至分片4。因此,本说明书提供的另一个实施例中,所述预定的分片策略可以包括:根据账户的注册地确定账户所属的分片。该注册地包括用户注册账户时通过客户端连接至区块链节点所归属的分片,或者用户注册账户时其IP所在的地理位置,或者用户填写/选择的归属地。对于后者,根据用户注册账户时其IP所在的地理位置或用户填写/选择的归属地,可以将该账户的状态存储分配至相同/相近地理位置的分片上,或者将该账户的状态存储分配至系统指定的分片上。
通过根据注册地来确定账户的所属分片的分片策略,可以将一些具有地域性的业务集中在同一个分片内处理,尽量将交易涉及新增、删除和修改的状态控制在单个分片内,可以有效减少跨分片的分布式事务,减少跨分片的消息交互和事务处理,进而可以提高系统吞吐量和性能。例如在一个区块链电子发票的区块链场景中,假如对应中国的省份划分有不同的分片,如广东的用户账户注册到广东的分片中,浙江的用户账户注册到浙江的分片中。在实际应用中,广东的用户通常在广东进行消费,与广东的其他用户发生交易的可能性更大;而浙江的用户通常是在浙江进行消费,与浙江的其他用户发生交易的可能性更大。那么广东的用户多数情况下也是在广东省内开发票,类似的,浙江的用户也多数是在浙江省内开发票。这样,基于用户的账户的注册地来划分确定账户的分片,可以极大的减少跨分片交易,降低区块链系统的复杂度。
此外,在另一个实施例中,本申请也提供一种按照业务关系配置账户的状态存储所属的分片。例如在区块链跨境汇款业务中,通过智能合约实现了跨境的转账交易,并且将链下资产锚定到链上发行的资产。通过客户端接入不同银行的账户,发生转账的交易对方可能不同。根据发生业务往来的频次和占比,可以将关联性大的账户的状态存储分配至同一分片。例如,区块链跨境汇款业务中,通过客户端接入银行1的账户a大部分转账发生在与通过客户端接入银行2的账户b之间,即账户a与账户b这两个账户的关联性较大,因此,可以将调用智能合约产生的与账户a和账户b相关的状态存储分配至相同的分片中。当然,上述提到的不同的分配方式中,可以根据业务关系动态调整分片存储的账户状态。
此外,如前所述,本说明书实施例提供的区块链分片机制也支持跨分片的交易,如通过提供可靠消息传输机制的中间节点或区块链主链。
当然,区块链系统中除了上述提到的一些汇款、电子发票的跨账户交易外,还存在一些单账户的交易,例如存证交易。这类单账户交易的发起账户,调用智能合约产生的状态存储,集中在发起账户本身,一般不涉及其他账户。由于不存在跨分片交易,适用上述状态存储方案时,可以更为高效、简单的提升吞吐量,提升区块链性能,并且易于克服存储瓶颈的问题。
本申请提供的所述状态存储方法,如图9所示,具体包括:
S91:归属于分片中的区块链节点执行调用合约的交易,产生待存储的与所述区块链外部账户相关的状态。
区块链中的交易可以支持创建和调用智能合约。对于创建合约的交易来说,区块链节点例如可以接收客户端发送的包含创建智能合约的交易,完成智能合约的部署。通过P2P网络,该创建智能合约的交易可以传播到其它区块链节点上(或是传播到其它大多数的区块链节点上)。每个接收到这个交易的区块链节点一般会对该交易进行验证和共识。例如对于有主共识算法,例如实用拜占庭容错(Practical Byzantine Fault Tolerance,PBFT),区块链共识网络中的主节点可以发起共识。共识达成后,区块链网络中的区块链节点可以在本地执行这个交易。具体的,区块链节点可以通过本地的虚拟机(例如以太坊虚拟机EVM)执行这个创建合约的交易,并生成对应的合约实例。合约创建后,区块链上出现一个与该智能合约对应的合约账户。该合约账户在区块链上的存储可以包括codehash和部署的合约代码(通常是合约代码的字节码)。codehash的值为部署的合约代码的hash值。这个合约账户一般拥有一个特定的地址。
此外,也可以是与区块链代码一同编译的原生合约,完成智能合约的部署。
智能合约中可以定义新的资产类型,例如前述程序代码片段中的balanceA。当然,在一个智能合约中,可以定义多个资产类型,例如balanceA、balanceB、balanceC、…。如前所述,智能合约中还可以定义状态变量。例如通过以太坊提供的solidity高级开发语言中,可以定义的状态变量包括两种类型,一种是基本数据类型的状态变量,另一种是映射(map或mapping)类型的状态变量。通过映射类型的状态变量,可以为每个外部账户赋予持有和交易这种新创建的数字资产的能力。如上述代码的例子,一般的,每个外部账户都可以对应一个balanceA类型的资产。那么,如果区块链的状态树中存在10000个外部账户,则通过智能合约,每个外部账户可以对应持有/交易balanceA类型的资产,即存在10000个“外部账户→balanceA”的映射。类似的,对于包括balanceB类型的资产,可以存在10000个“外部账户→balanceB”的映射。以此类推。如前所述,除了映射数据结构,还可以通过其它数据结构定义外部账户地址到一种资产类型的映射,这里并不限制。以下以映射形式的数据结构举例说明。
这个合约成功创建之后,后续外部账户可以调用这个合约。智能合约可以以合约代码中规定的方式在区块链网络中每个节点独立的执行,执行的交易、产生的状态和交易的回执可以保存在区块链上。调用合约一般可以通过发起交易的形式。交易的from字段是发起调用智能合约的账户的地址,to字段中可以表示被调用的智能合约的地址,交易的data字段可以包括调用智能合约的方法和传入的参数。通过调用智能合约,映射中外部账户对应的合约状态可能发生变化,例如外部账户对应的某一资产类型的余额可能会发生改变。这样,映射中的value值会发生变化。变化后的value值需要存储在区块链上。这样,所述合约状态包括对应区块链外部账号的状态。
如前所述,所述待存储的合约状态包括合约中定义的外部账户与资产的映射关系。具体的,所述合约中可以通过映射数据结构或其它数据结构定义这种映射关系。以映射这种数据结构定义为例,该映射中定义的一般是外部账号与资产的映射关系。如果在智能合约中定义了一种新的资产,如定义了一种balanceA的资产,则通过映射可以定义外部账号与这个balanceA类型资产的映射关系。此外,可以通过对编译器、虚拟机中的适配,设置一种定义类似数据结构的方式,如:
schema {
uint256 balanceP;
bool owner_flag;
};
上述代码示例也可以定义外部账户与资产的映射关系。具体的,uint256表示定义了一种名为balanceP的资产类型,为无符号整数,256bit长度。bool表示布尔类型变量,对应外部账户的标识owner_flag。这样,通过这种方式也实现了定义外部账户与资产的映射关系。当然,需要编译器和虚拟机的适配以支持合约中这样的定义方式。
客户端可以发起调用合约的交易至区块链系统。区块链系统中,可以由前述的主链接收所述调用合约的交易,并将该交易路由至存储所述外部账户的分片内。该调用合约的交易中,执行后一般涉及相关的外部账户的状态发生变化。所述发生变化后的外部账户的状态,包括合约中涉及的相关外部账户的状态,如通过映射数据结构定义的外部账户与资产的映射关系,需要存储至对应分片的节点的状态存储中。所述主链可以作为接收所述交易和路由所述交易的角色。所述路由交易,例如可以根据该调用合约的交易涉及的发生状态改变的外部账户,将该交易路由至存储所述外部账户的分片内。具体的,所述主链按照区块链系统采用的取模、分段、注册地之类的策略将该交易路由至存储所述外部账户的分片内。
进而,归属于分片中的区块链节点可以执行调用合约的交易,并产生待存储的与所述区块链外部账户相关的状态。
此外,与S91类似的,归属于分片中的区块链节点还可以是执行创建合约的交易。执行创建合约的交易的过程中,也可能产生待存储的与所述区块链外部账户相关的状态,例如对外无账户相关的状态进行初始化。以下主要以执行调用合约的交易为例进行说明,执行创建合约的交易与此类似,不再赘述。对于创建合约的交易,类似的,可以是由前述的主链接收所述创建合约的交易,并将该交易路由至存储所述外部账户的分片内。
S93:将所述待存储的与所述区块链外部账户相关的状态存储到对应的区块链外部账户的状态存储中。
如图5、图6、图7、图8中所示,storage中的映射类型状态变量可以以key-value形式存储。具体的一个例子中,对于映射类型,key = SHA3(映射中的关键字,变量声明位置),也就是把映射中的关键字和变量声明位置拼在一起成为一定长度(例如64字节)的字符串后计算hash值。value可以存储变量的实际值。
最简单的情形例如图7所示,一个区块链系统中创建了一个智能合约,而且该智能合约中定义了一种新类型的资产。而且,创建的合约中,可以仅定义一种新类型的资产,或者是定义多种新类型资产的情况下仅启用其中的一种(而另外的新类型资产未启用或未初始化)。这种情况下,由于每个外部账户对应一种类型的资产的余额,所以该类型的资产的余额可以不需要组织成树的形式,通过一个key-value即可以存储。其中,这个映射类型中,key = SHA3(映射中的关键字,变量声明位置),也就是把映射中的关键字和变量声明位置拼在一起成为一定长度(例如64字节)的字符串后计算hash值。value可以存储变量的实际值,即balanceA类型的资产的余额。这样,外部账户的storage_root可以是这个key-value的hash值。每个外部账户都可以有一个这样的映射数据。例如,外部账户1的storage_root指向其映射类型中一个key-value;外部账户2指向其映射类型中一个key-value;以此类推。综上,对于区块链系统中仅有一个智能合约的情况,且该智能合约中仅定义或启用了一种新类型的资产,则区块链中的状态树的存储包括两层;第一层通过树形结构在每个叶子节点中存储一个外部账户相关的包括所述新类型资产的key-value的hash值;第二层存储所述映射定义的包括所述外部账号与所述新类型资产的key-value形式的映射关系。
前面提到,在一个智能合约中,可以定义多个资产类型,例如balanceA、balanceB、balanceC、balanceD、…。这样,每个外部账户可以有分别对应balanceA、balanceB、balanceC、balanceD、…类型的资产的余额。这种情况下,由于每个外部账户对应多种类型的资产的余额,该多种类型的资产的余额可以组织成树的形式。如图6中所示,在第二层的存储树中,通过节点1、节点2、节点3共三个节点来示意性的表示一种树的形式。这个树例如是MPT树,则节点1、节点2、节点3可以示意性的表示MPT树中的扩展节点、分支节点。其中,这个映射类型中,key = SHA3(映射中的关键字,变量声明位置),也就是把映射中的关键字和变量声明位置拼在一起成为一定长度(例如64字节)的字符串后计算hash值。value可以存储变量的实际值,即balanceA、balanceB、balanceC、balanceD、…类型的资产的余额。如图6中,外部账户1的存储树的叶子节点分别具有balanceA、balanceB、balanceC、balanceD、…类型的资产的余额。这样,外部账户的storage_root可以是balanceA、balanceB、balanceC、balanceD、…类型的资产的key-value组成树的形式后的根hash值。每个外部账户都可以有一个这样的映射数据。例如,外部账户1的storage_root指向其映射类型中一组key-value的树形结构;外部账户2的storage_root指向其映射类型中一组key-value的树形结构。以此类推。这样,对于区块链系统中仅有一个智能合约的情况,且该智能合约中定义且启用了至少两种新类型的资产,则区块链中状态树的存储包括两层;第一层通过树形结构在每个叶子节点中存储一个外部账户相关的包括所有所述新类型资产的key-value的根hash值;第二层通过树形结构在每个叶子节点中存储所述映射定义的包括所述外部账号与一种所述新类型资产的key-value形式的映射关系。
在一个区块链系统中,可以创建多个智能合约。例如一个区块链系统中创建了多个智能合约,这些智能合约可以通过树形结构组织起来,如图8所示,即如图中的第二层为合约存储树。大多数智能合约中的每个,可以定义一种或多种新类型的资产。每个智能合约中,有不同的状态。例如图8中,通过树形结构连接外部账户1的,示出了两个合约。每个合约基于其ID、storage_root可以计算得到一个hash值,该hash值可以存储于第二层树形结构的一个叶子节点中,如图中的schematic_storage_root中。对于这两个创建的合约中的每个仅定义一种新类型的资产的情况,或者是定义多种新类型资产的情况下仅启用其中的一种(而另外的新类型资产未启用或未初始化)的情况,每个合约对应一种类型的资产的余额,所以该类型的资产的余额可以不需要组织成树的形式,通过一个key-value即可以存储,类似图7中的第二层结构。这样,一个智能合约的storage_root可以是这个key-value的hash值。以此类推。综上,对于区块链系统中有至少两个智能合约的情况,且该智能合约中仅定义或启用了一种新类型的资产,则区块链中状态树的存储包括三层;第一层通过树形结构在每个叶子节点中存储与一个外部账户相关的包括所有智能合约涉及信息的根hash值;第二层通过树形结构在每个叶子节点中存储一个外部账户相关的包括一个智能合约涉及的所述新类型资产的key-value的hash值;第三层存储所述映射定义的包括所述外部账号与所述资产的key-value形式的映射关系。
在一个区块链系统中,可以创建多个智能合约,并且每个合约中可以定义多个资产类型,例如balanceA、balanceB、balanceC、balanceD、…。该情况可以如图5所示。通过树形结构连接外部账户1的,示出了两个合约。即为第二层合约存储树。实际上,第二层的存储可以包括多个智能合约,即可以有多个叶子节点。每个合约基于其ID、storage_root可以计算得到一个hash值,该hash值可以存储于第二层树形结构的一个叶子节点中,如图中的schematic_storage_root中。第二层的每个叶子节点可以用来存储该外部账户下涉及的一个智能合约的存储的根hash值,可以基于包括该外部账户涉及的合约ID(contract ID)、storage的hash值计算得到。第三层为存储树。具体的,第三层树形结构的根节点为外部账户涉及的智能合约中的状态变量的根hash值。类似的,第三层可以通过以节点1、节点2、节点3共三个节点来示意性的表示MPT树的形式,具体的,可以表示MPT树中的扩展节点、分支节点。第三层的每个叶子节点可以用来存储合约中的一个状态变量的value值。上述的三层树的结构,每棵树的根节点到叶子节点的路径上存储的一部分数据连起来可以构成key,叶子节点中可以存储value。这样,通过这样的存储模型,可以在每个外部账户下存储该外部账户涉及的每个智能合约中的状态变量的key-value。综上,对于区块链系统中有至少两个智能合约的情况,且该智能合约中仅定义或启用了至少两种新类型的资产,则区块链中状态树的存储包括三层;第一层通过树形结构在每个叶子节点中存储与一个外部账户相关的包括所有智能合约涉及信息的根hash值;第二层通过树形结构在每个叶子节点中存储一个外部账户相关的包括一个智能合约涉及的所有所述新类型资产的key-value的根hash值;第三层通过树形结构在每个叶子节点存储所述映射定义的包括所述外部账号与一种所述新类型资产的key-value形式的映射关系。
上述图5-8的示例中,所述第一层通过树形结构在每个叶子节点中还可以存储该外部账户的交易计数。
上述图5、图8的示例中,显示出所述第二层通过树形结构在每个叶子节点中还存储关联的智能合约的编号的情形。此外,所述第二层还可以不在每个叶子节点中存储关联的智能合约的编号,而是第二层的根节点通过第二层的树形结构到第二层每个叶子节点的路径中存储涉及的智能合约的地址或基于所述涉及的智能合约的地址的映射值。
前述提到,智能合约中可以定义的状态变量包括两种类型,一种是基本数据类型的状态变量,另一种是映射(map或mapping)类型的状态变量。上述map映射类型的状态变量,与每个外部账户有关。这样,对于每个外部账户来说,这个映射类型的状态变量是局部类型的状态变量。此外,智能合约中定义的基本数据类型,可能与每个外部账户都相关,而不仅仅是与一个外部账户相关。这样,基本数据类型的状态变量,属于全局类型的状态变量。
此外,如前所述,创建智能合约后,会出现合约账户。该合约账户也可能与每个外部账户相关,而不仅仅是与一个外部账户相关。例如,一个关于打赌的智能合约中,约定了外部账户A和外部账户B在第二天天气条件下的转账情况。如第二天是晴天,则外部账户A将转账一笔资产(如50元)至外部账户B,如第二天不是晴天,则外部账户B将转账一笔资产(如50元)至外部账户A。而在外部账户A和外部账户B调用这个智能合约时,需要各自将一笔资产(如50元)转入合约账户。这样,合约账户中的状态变量也属于全局类型的状态变量。
前述通过图5-8示例出了局部类型状态变量的存储。以下说明全局类型状态变量的存储。
第一种方式是,在合约账户中,设置智能合约中基本数据类型的状态变量以及合约账户的状态变量的存储。例如,在合约账户的storage中存储基本数据类型的状态变量以及合约账户的状态变量。在图5的基础上,以图12为例加以说明。区块头中的state_root存储整个状态树的根节点的hash值。第一层树形结构的叶子节点可以用来存储外部账户存储和合约账户存储的根hash值。外部账户和合约账户可以分别有若干个。第一层叶子节点中每个合约账户的账户信息的根hash,可以基于包括该合约账户的nonce、balance、codehash以及该合约账户涉及的智能合约的存储的根hash值计算得到。所述智能合约的存储的根hash值如图12中合约账户 2的storage_root。类似的,第二层可以通过一个以节点1、节点2、节点3共三个节点来示意性的表示MPT树的形式。第二层的每个叶子节点可以用来存储该合约账户下涉及的一个全局类型的状态变量。如前所述,这个合约账户涉及的状态变量,可以是基本数据类型,也可以是合约账户中的状态变量。具体的,该层树形结构的根节点为所述合约账户涉及的智能合约中全局类型的状态变量的根hash值。类似的,该层可以通过一个以节点1、节点2、节点3共三个节点来示意性的表示MPT树的形式,具体的,可以表示MPT树中的扩展节点、分支节点。第三层的每个叶子节点可以用来存储合约中的一个状态变量的value值。上述树的结构,每棵树的根节点到叶子节点的路径上存储的一部分数据连起来可以构成key,叶子节点中可以存储value。这样,通过这样的存储模型,可以存储该合约账户涉及的全局类型的状态变量的key-value。
这样,对于区块链节点执行调用合约的交易,产生待存储的与所述区块链合约账户相关的状态,例如产生所述合约中基本数据类型的状态变量以及合约账户的状态变量的情况,可以将所述待存储的与所述区块链合约账户相关的状态存储到对应的区块链合约账户的状态存储中,即将所述待存储的合约中基本数据类型的状态变量以及合约账户的状态变量存储到对应的区块链合约账户的状态存储中。区块链合约账户的状态存储中通过树形结构存储所述区块链合约账户涉及的全局类型的状态变量的key-value的映射关系,具体与前述类似,不再赘述。
第二种方式是,在合约账户中,可以不再设置合约状态相关的存储storage,而是设置一个独立于所述外部账户存储以及所述合约账户存储的全局状态存储。这样,可以将所述待存储的与所述区块链合约账户相关的状态存储到独立于所述外部账户存储以及所述合约账户存储的全局状态存储中,即将所述待存储的合约中基本数据类型的状态变量以及合约账户的状态变量存储到独立于所述外部账户存储以及所述合约账户存储的全局状态存储中。具体的,所述全局状态存储中,可以通过树形结构存储所述区块链合约账户相关的状态的key-value的映射关系,即将所述待存储的合约中基本数据类型的状态变量以及合约账户的状态变量通过树形结构存储到独立于所述外部账户存储以及所述合约账户存储的全局状态存储中。
此外,还可以有第三种方式,即将所述待存储的合约账户的状态变量存储到对应的区块链合约账户的状态存储中,而将所述基本数据类型的状态变量存储到独立于所述外部账户存储以及所述合约账户存储的全局状态存储中。具体的,可以是在所述合约账户的状态存储中通过树形结构存储所述区块链合约账户的状态变量的key-value的映射关系,在所述全局状态存储中通过树形结构存储所述基本数据类型的状态变量的key-value的映射关系。
上述的树形结构,可以采用16叉树。一般的,一个智能合约中的全局状态不超过32个状态变量。采用16叉树,可以采用两层树结构。则第二层树结构中,可以包括16*16=256个叶子节点,远大于32,因此可以满足一般的一个智能合约中可能包括的全局状态的数量。
需要说明的是,本说明书提到的区块链节点,侧重逻辑节点的概念。也就是说,一个物理节点也可以从逻辑上划分为多个逻辑的节点。当然,本说明书中的区块链节点也可以适用于物理节点的情形。
通过上述本申请的实施例,区块链系统中至少包括两个分片,不同分片中的节点存储不同的外部账户集合的状态,并且将待存储的与所述区块链外部账户相关的状态存储到对应的区块链外部账户的状态存储中,每个外部账户的状态存储对应的外部账户相关的状态,进而将使区块链系统中不同的分片存储不同的外部账户集合的状态。这样,避免了单账户热点的问题,同时,每个分片承担的状态存储的负载压力比较小,可以提升整个区块链系统的性能。而且,分散到各个外部账户的状态存储后,由于一个外部账户的状态数量相对比较少,并不存储完整的区块链状态,从而能够解决存储能力瓶颈问题。同时,本申请的方式,并不会像图3中的将所有外部账户的状态集中于合约账户的状态存储中,从而可以大大降低每个外部账户的树形结构的深度,进而缩短了查找、更新外部账户的时间,提升了区块链存储的读写效率。
对于全局状态,即使采用上述第一种的方式全部存储于合约账户的状态存储中,一般也可以满足32个全局状态数量的要求,即采用两层深度的属性结构可以满足存储的需求,从而也可以大大降低树的深度。采用上述第二种或第三种方式,同样可以大大降低树的深度。
如图10所示,本申请实施例还提供一种区块链系统,该区块链系统中至少包括两个分片,不同分片中的节点用于存储不同的外部账户集合的状态;且,
归属于分片中的区块链节点执行调用合约的交易而产生的与所述区块链外部账户相关的状态,存储于对应的区块链外部账户的状态存储中。
所述与所述区块链外部账户相关的状态可以包括:
所述合约中定义的外部账户与资产的映射关系。
所述合约中定义的外部账户与资产的映射关系可以包括:
通过映射数据结构定义的外部账户与资产的映射关系。
所述通过映射数据结构定义的外部账户与资产的映射关系可以通过key-value来存储。
对于区块链系统中仅有一个智能合约的情况,且该智能合约中仅定义或启用了一种新类型的资产,则区块链中状态树的存储可以包括两层;
第一层通过树形结构在每个叶子节点中存储一个外部账户相关的包括所述新类型资产的key-value的hash值;
第二层存储定义的包括所述外部账户与所述新类型资产的key-value的映射关系。
对于区块链系统中仅有一个智能合约的情况,且该智能合约中定义且启用了至少两种新类型的资产,则区块链中状态树的存储可以包括两层;
第一层通过树形结构在每个叶子节点中存储一个外部账户相关的包括所有所述新类型资产的key-value的根hash值;
第二层通过树形结构在每个叶子节点中存储定义的包括所述外部账户与一种所述新类型资产的key-value的映射关系。
对于区块链系统中有至少两个智能合约的情况,且该智能合约中仅定义或启用了一种新类型的资产,则区块链中状态树的存储可以包括三层;
第一层通过树形结构在每个叶子节点中存储与一个外部账户相关的包括所有智能合约涉及信息的根hash值;
第二层通过树形结构在每个叶子节点中存储一个外部账户相关的包括一个智能合约涉及的所述新类型资产的key-value的hash值;
第三层存储定义的包括所述外部账户与所述资产的key-value的映射关系。
对于区块链系统中有至少两个智能合约的情况,且该智能合约中定义或启用了至少两种新类型的资产,则区块链中状态树的存储可以包括三层;
第一层通过树形结构在每个叶子节点中存储与一个外部账户相关的包括所有智能合约涉及信息的根hash值;
第二层通过树形结构在每个叶子节点中存储一个外部账户相关的包括一个智能合约涉及的所有所述新类型资产的key-value的根hash值;
第三层通过树形结构在每个叶子节点存储定义的包括所述外部账户与一种所述新类型资产的key-value的映射关系。
所述第一层通过树形结构在每个叶子节点中还可以存储该外部账户的交易计数。
所述第二层通过树形结构在每个叶子节点中还可以存储关联的智能合约的编号。
所述区块链节点执行调用合约的交易产生的与所述区块链合约账户相关的状态可以存储于对应的区块链合约账户的状态存储中。
所述与区块链合约账户相关的状态可以包括所述合约中基本数据类型的状态变量以及合约账户的状态变量;所述合约账户的状态存储中可以通过树形结构存储所述区块链合约账户相关的状态的key-value的映射关系。
所述区块链节点执行调用合约的交易产生的与所述区块链合约账户相关的状态可以存储于独立于所述外部账户存储以及所述合约账户存储的全局状态存储中;所述全局状态存储中可以通过树形结构存储所述区块链合约账户相关的状态的key-value的映射关系。
所述合约账户的状态变量可以存储于对应的区块链合约账户的状态存储中;所述合约账户的状态存储中可以通过树形结构存储所述区块链合约账户的状态变量的key-value的映射关系;
所述基本数据类型的状态变量可以存储于独立于所述外部账户存储以及所述合约账户存储的全局状态存储中;所述全局状态存储中可以通过树形结构存储所述基本数据类型的状态变量的key-value的映射关系。
所述不同分片中的节点存储不同的外部账户集合的状态,可以包括:
不同分片对应的外部账户,根据外部账户的唯一标识分别从不同的初始值开始以相同的间隔构成外部账户集合;或,
不同分片对应的外部账户,根据外部账户的唯一标识分段后构成外部账户账户集合;或,
基于外部账户的唯一标识采用一致性哈希的方式将所述外部账户的状态存储分配至相应的分片上;或,
根据账户的注册地确定账户所属的分片。
所述注册地可以包括:
用户注册账户时通过客户端连接至区块链节点所归属的分片;或,
用户注册账户时其IP所在的地理位置;或,
用户填写/选择的归属地。
根据用户注册账户时其IP所在的地理位置或用户填写/选择的归属地,可以将该账户的状态存储分配至相同/相近地理位置的分片上,也可以将该账户的状态存储分配至系统指定的分片上。
所述不同分片中的节点存储不同的外部账户集合的状态,可以包括:
按照业务关系配置账户的状态存储所属的分片。
所述区块链系统还可以包括主链,用于接收所述调用合约的交易,并将该交易路由至存储所述外部账户的分片内。
所述由主链接收所述调用合约的交易,可以根据该调用合约的交易涉及的发生状态改变的外部账户,将该交易路由至存储所述外部账户的分片内。
如图13所示,本申请一实施例还提供一种区块链节点,该区块链节点归属于区块链系统中的一个分片,包括:
存储单元132,用于存储外部账户集合的状态,且对应的外部账户集合不同于其它分片中的区块链节点中的外部账户集合;
执行单元131,用于执行如前所述的状态存储方法。
如图14所示,本申请一实施例还提供一种区块链节点,该区块链节点归属于区块链系统中的一个分片,用于存储外部账户集合的状态,且对应的外部账户集合不同于其它分片中的区块链节点中的外部账户集合;
所述区块链节点包括:
处理器141;
存储器142,其中存储有程序,其中在所述处理器执行所述程序时,执行如前所述的状态存储方法。
上述状态分片方案,是本申请中给出的一种解决方案。除此之外,还可能存在其它状态分片方案。不论对于何种状态分片方案,只要不同分片中的节点存储不同的外部账户集合的状态,都会涉及确定不同分片的全部账户的世界状态的问题。
例如,分片1中的某一账户可能会发生与分片2中的另一账户相关的一笔交易,例如普通转账交易。具体的,例如由分片1中的某一账户转账至分片2中的另一账户,或者分片1中的某一账户发起某个调用合约的交易,而该被调用的合约在执行时,涉及对分片2中某一账户的操作。调用合约的情况,按照前述所述的合约中定义的外部账户与资产的映射关系,具体的一个例子中,例如是分片1中某一账户发起偿还某新资产类型,该资产类型下的账户(包括外部账户和合约账户)各自具有一定的余额(balance)。如图15中的分片1中的外部账户1将一定数量的该类型的资产转移至合约账户,再按照合约中的条件,由合约账户转移至如图15中分片2的外部账户6。
显然的,上述例子涉及跨分片的交易。本申请提出一种基于主链的跨分片交易方法,能够在基于主链的区块链分片系统中实现。本申请的基于主链的区块链分片系统例如如图15所示,除了若干分片以外,还存在主链。主链包括若干区块链节点,如图中的Q1、Q2、Q3和Q4。主链与各个分片相连。如前所述,尽管图示中各个分片之间通过连接线示意出各个分片之间相连,但是,也可能各个分片并非是全部互通的,或者是每个分片均不与其它分片相通。对于最后一种情况,也就是说,各个分片之间可以互不相连,而仅与主链相连。这里,分片之间相通,可以是一个分片中的一个节点与另一分片中的任一节点都相通,也可以是一个分片中的一个节点与另一分片中的一个或部分节点相通。类似的,分片与主链相通,可以是分片中的一个节点与主链中的任一节点都相通或分片中的一个节点主链中的一个或部分节点相通,也可以是主链中的一个节点与分片中的任一节点都相通或分片中的一个或部分节点相通。
不同分片中的节点可以存储不同的外部账户集合的状态,包括上述如图5-12中对应的实施例中执行创建和/或调用合约的交易而产生的与外部账户相关的状态,也可以是普通转账交易产生的外部账户的状态。对于不采用本申请图5-12对应实施例的状态分片方案,而是将执行创建和/或调用合约的交易产生的与外部账户相关的状态存储于合约账户的状态存储中,可能存在不同分片中的节点存储不同合约账户状态的集合的情况,或者不同分片中的节点存储不同合约账户集合的状态的情况,也适用于下面将要提到的本申请的方案。所述不同分片中的节点存储不同合约账户状态的集合的情况,例如区块链系统存在一个合约,该合约对应的合约账户具有不同的状态,如状态a、状态b、状态c和状态d,较为简单的可以是分片1中的节点存储状态集合{a},分片2中的节点存储状态集合{b},分片3中的节点存储状态集合{c},分片4中的节点存储状态集合{d}。所述不同分片中的节点存储不同合约账户集合的状态的情况,例如整个区块链系统存在4个合约,分别为合约1、合约2、合约3和合约4,则分别对应合约账户1、合约账户2、合约账户3和合约账户4,较为简单的可以是分片1中的节点存储状态集合{合约账户1的状态},分片2中的节点存储状态集合{合约账户2的状态},分片3中的节点存储状态集合{合约账户3的状态},分片4中的节点存储状态集合{合约账户4的状态}。此外,可以理解的,对于存在多个合约且每个合约具有多个状态,也可以是上述两种情况的混合。上述各种情况,笼统的说,可以称为不同分片存储不同的状态集合。
对于不同分片存储不同的状态集合,本申请提出的方案中引入主链,示意性的架构如图16所示。如图16中,分片1和分片2的产生新区块的步调可以不一致;当然,也可以步调一致,这里主要以步调不一致加以说明。需要说明的是,这里为了简便,仅示出了2个分片的情况,多于2个分片的情况与此类似,不再赘述。而且,仅示出了分片1顺序产生区块101和102的情况,以及分片2中顺序产生区块201和202的情况。实际上,可以理解的,分片中处理交易请求,可以通过共识机制生成区块。生成的区块的区块号一般是连续的,并且下一区块的区块头中通过一个字段锁定了上一区块的hash值,例如通过如图3中的Prev Hash字段来锁定。一个区块的hash值一般是该区块头中所有字段的hash结果。在分片生成的区块的区块头中,如图3中所示,一般可以包括区块号(Block Num),时间戳(Timestamp),前一个区块的hash值(Prev Hash),以及交易根hash(Transaction_Root)、状态根hash(State_Root),还可以包括收据根hash(Receipt_Root)和随机数(Nonce)。在分片生成的区块的区块体中,如图3所示,一般可以包括原始交易列表,这些交易可以通过树形结构组织,如前述提到的MPT树,或者是merkle树等。通过树形结构组织的原始交易列表的树根的hash值,存放于区块头的Transaction_Root中。如前所述,state_root可以是当前区块链中所有账户的状态组成的MPT树的根的哈希值,即指向state_root的为一棵MPT形式的状态树。对于区块头中包括Receipt_Root的,Receipt_Root可以是当前区块中所有收据组成的Merkle或MPT树的根的hash值。
例如,分片1顺序产生区块101和102,分片2产生区块201和202。分片1在区块101有对应的状态集合,在区块102有对应的状态集合。分片2在区块201有对应的状态集合,在区块202有对应的状态集合。
本申请实施例中,提供了包含主链的区块链分片的系统。主链中可以包括若干节点。一般的,主链中的节点具有较高的可信度,并且这些节点构成的主链符合拜占庭容错要求。主链可以具有自己的时钟,如图16中所示的主链时间轴即表达主链时钟的时间轴。按照主链的时间轴,分片2区块201的生成时间在主链区块10001的生成时间和主链区块10002的生成时间之间,分片1区块101的生成时间在主链区块10002的生成时间和主链区块10003的生成时间之间,分片2区块202的生成时间在主链区块10003的生成时间和主链区块10004的生成时间之间,分片1区块102的生成时间主链区块10004的生成时间之后。
例如,分片1在时刻之前收到客户端发起的一笔交易,例如是普通转账交易,该交易是由分片1中的外部账户1转账至分片2中的外部账户6。分片1收到该交易后,一段时间之后,可以由分片1中的主节点将包括该交易在内的一定数量的交易打包成区块,在分片1中经过共识后,由分片1中的各个节点执行该交易。由于该交易是跨片交易,分片1中仅能执行在外部账户1中扣减一定余额的操作。剩余的在分片2中执行为外部账户6增加一定余额的操作,需要由分片2中的节点来执行。那么,这个过程需要将分片1中接收到的交易的部分操作转发至分片2中,交由分片2来执行。
再例如,分片1在时刻之前收到客户端发起的一笔交易,例如是调用合约的交易,该交易是由分片1中的外部账户1发起对某个智能合约的调用。分片1收到该交易后,一段时间之后,可以由分片1中的主节点将包括该交易在内的一定数量的交易打包成区块,在分片1中经过共识后,由分片1中的各个节点执行该交易。该交易中的智能合约在执行过程中,可能涉及跨片交易。如前述的例子,分片1中某一账户发起偿还一定数量的某新资产类型,该资产类型下的账户(包括外部账户和合约账户)各自具有一定的余额(balance)。如图15中的分片1中的外部账户1将一定数量的该类型的资产转移至合约账户,再按照合约中的条件,由合约账户转移至如图15中分片2的外部账户6。分片1中可以执行在外部账户1中扣减一定余额新资产类型的操作;分片2中可以执行为外部账户6增加一定余额新资产类型的操作,而且这个操作需要由分片2中的节点来执行(合约账户的操作本申请中先暂不涉及)。那么,这个过程需要将分片1中接收到的交易的部分操作转发至分片2中,交由分片2来执行。
也就是说,客户端向源分片发起的交易中可以包括跨分片交易,这样的交易的执行,可能既涉及对源分片存储的状态集合中的状态的改变,还涉及对目标分片存储的状态集合中的状态的改变。对于跨分片交易中需要由目标分片执行的操作,可以由源分片发送至主链。
源分片(例如分片1)发送至主链的这些操作例如如下表1:
分片1发来的跨片交易中需要由目标分片2执行的操作; |
分片1发来的跨片交易中需要由目标分片3执行的操作; |
...... |
分片1发来的跨片交易中需要由目标分片n-1执行的操作; |
分片1发来的跨片交易中需要由目标分片n执行的操作; |
表1
本申请中,可以通过基于包含主链的区块分片系统执行。由于主链中的节点具有较高的可信度,因此可以将一个分片(后续称为源分片)中接收的跨分片的交易中涉及其它分片(后续称为目标分片)的操作发送至主链,并由主链转发至所述的目标分片。一般的,主链上生成区块的频率一般高于各个分片中生成区块的频率,至少不低于各个分片中生成区块的频率。交易的执行会导致状态发生改变。对于多个交易的执行来说,这些交易的执行顺序需要是确定的,否则将可能会导致状态的改变发生错误,甚至导致某些交易无法执行。目标分片执行主链中打包的跨分片交易中所述目标分片需要执行的操作,应当按照主链上转发的交易的顺序来执行。为了保持目标分片在执行主链转发的交易时是按照主链转发的交易的顺序执行性的,而不是乱序执行的,也不是故意跳过某些主链区块中打包的交易,需要在目标分片上记录执行到哪个主链区块中的跨片交易。那么,需要通过一定的消息机制和区块的设计来将主链中产生的需要由目标分片执行的跨片交易的内容锁定到目标分片的区块中。
主链上生成的区块,可以通过hash来锁定,例如主链中的区块10002的区块头的Prev Hash中存储上一区块10001的hash值,以此类推。如图17所示,主链的区块的区块头(区块nHeader)中,可以包括区块号(Block Num),时间戳(Timestamp),前一个区块的hash值(Prev Hash)等字段,以及区块体中包含交易所构成的树的树根的hash值。主链区块的区块体(区块nBody)中,可以包括该主链区块生成之前的各个分片发送至该主链的跨片交易中,需要目标分片所执行的操作。优选的,主链区块的区块体包括的主链区块生成之前的各个分片发送至该主链的跨片交易中需要目标分片所做的操作,是未经主链在之前已生成的区块中打包的。例如,区块10002的区块体(区块10002Body)中,可以包括如下表2:
分片1发来的跨片交易中需要由目标分片2执行的操作; |
...... |
分片1发来的跨片交易中需要由目标分片n执行的操作; |
分片2发来的跨片交易中需要由目标分片1执行的操作; |
分片2发来的跨片交易中需要由目标分片3执行的操作; |
...... |
分片2发来的跨片交易中需要由目标分片n执行的操作; |
...... |
分片n发来的跨片交易中需要由目标分片1执行的操作; |
...... |
分片n发来的跨片交易中需要由目标分片(n-1)执行的操作。 |
表2
上述区块头中的交易根hash(Transaction root),可以是将交易体中的这些需要目标分片执行的操作的hash值组织成树的形式,从而得到树根的hash值。这样的树例如是merkle树或者MPT树。从而,通过merkle树或者MPT树,可以将各个分片发送至主链的跨片交易中需要目标分片执行的操作的hash值锁定到主链区块的区块头中。
需要说明的是,对于没有产生的分片发来的跨片交易,上述表格中可以不包括相应的需要由目标分片执行的操作的那一行,或者,对应的那一行是空。优选的,可以是不包括相应的需要由目标分片执行的操作的那一行,这样在很多情况下可以降低交易根hash的hash计算量。
接下来,执行如图19的内容:
S191:主链根据主链区块中的跨片交易涉及的目标分片将所述主链区块的区块体中跨分片交易需要目标分片执行的操作发送至对应的目标分片。
图17中,分片2可以作为源分片,在区块202中打包的原始交易列表中,可以包括跨分片交易。这些跨分片交易中需要由目标分片执行的操作,例如上面的表1,可以由分片2发送至主链。
主链生成主链区块的过程中,可以将接收到的所述源分片发来的跨片交易中需要目标分片执行的跨片交易的操作填入主链区块的区块体中,并可以将所述区块体中各个操作的hash值按照树形结构计算得到的根的hash值填入主链区块的区块头的交易根hash(Transaction_root)中,例如如图17中所示。
进而,主链在生成的主链区块10004中(如图中所示,主链区块10004的生成时间在源分片区块202之前),在区块体中可以包括分片2发来的这些内容,当然也可以包括其它分片作为源分片发来的需要其相对的目标分片执行的跨分片交易的操作。这样,主链区块的区块体中可以包括所有目标区块需要执行的跨片交易中的相应操作。这些内容可以如上面表2中所示。
主链区块10004的区块头中,可以由Transaction_root来锁定区块体中的这些内容。具体如前所述,可以通过树形结构组织区块体中的这些内容,生成树根,进而将树根的hash值存放于区块头的Transaction_root中。
这样,可以由主链对跨分片交易的需要由目标分片执行的操作在主链上进行存证。
另一方面,主链可以根据主链区块中的跨片交易涉及的目标分片将所述主链区块发送至对应目标分片。具体的,主链可以按照目标分片重新对表2中的内容按照目标分片来分组,例如如下面的表3所示:
目标分片1需要执行的跨分片交易中的操作(跨分片交易由源分片2发出); |
...... |
目标分片1需要执行的跨分片交易中的操作(跨分片交易由原分片n发出); |
目标分片2需要执行的跨分片交易中的操作(跨分片交易由源分片1发出); |
...... |
目标分片2需要执行的跨分片交易中的操作(跨分片交易由源分片n发出); |
...... |
目标分片n需要执行的跨分片交易中的操作(跨分片交易由源分片1发出); |
...... |
目标分片n需要执行的跨分片交易中的操作(跨分片交易由源分片n-1发出)。 |
表3
这样,主链可以根据涉及的目标分片将表3中的内容发送至对应的目标分片中。例如,发送至目标分片1的内容如下表4中所示:
目标分片1需要执行的跨分片交易中的操作(跨分片交易由源分片2发出); |
...... |
目标分片1需要执行的跨分片交易中的操作(跨分片交易由原分片n发出); |
表4
再例如,发送至目标分片2的内容如下表5中所示:
目标分片2需要执行的跨分片交易中的操作(跨分片交易由源分片1发出); |
...... |
目标分片2需要执行的跨分片交易中的操作(跨分片交易由源分片n发出); |
...... |
表5
以此类推。
S193:接收到所述主链区块的目标分片在生成分片区块的过程中,将接收到的需要由该目标分片执行的操作填入所述分片区块的区块体中。
以目标分片为分片1为例,如图18所示。分片1接收到主链发来的如上表4中的内容,即跨分片交易中需要由目标分片执行的操作。上表4中的内容,分片1将打包到生成的分片区块101中,并执行区块101中打包的交易。当然,分片1还可以接收其它交易,例如分片1对应的客户端发来的交易,并可以将这些交易与上述跨分片交易中需要由目标分片执行的操作一并打包进生成的区块中。这些打包的交易,如前所述,可以位于生成的区块的区块体中,如图18的区块102的body中的原始交易列表中。
如前所述,打包进102区块body中的交易,可能需要经过分片1中各个节点的共识过程。这些交易,可以包括普通转账交易中跨分片的交易,也可以包括与合约相关的跨分片交易。进而,目标分片中的各个节点可以执行上述需要由本分片执行的交易。
此外,目标分片生成的区块头中,可以由Transaction_root来锁定区块体中的这些内容。
接收到所述主链区块的目标分片在生成分片区块的过程中,将接收到的最新主链区块hash填入所述分片区块的区块头中。具体如前所述,可以通过树形结构组织区块体中的这些内容,生成树根,进而将树根的hash值存放于区块头的Transaction_root中。这样,可以由目标分片对跨分片交易的需要由该目标分片执行的操作在分片链上进行存证。如图18中,区块102的区块头的Transaction_root字段,可以存放区块体body中原始交易列表中的各交易经由树形结构组成而生成的根节点的hash值。
另外,主链还可以将主链区块的区块头发送至分片,这样,分片在生成分片的过程中,可以根据主链区块的区块头计算主链区块的hash值,进而将得到的主链区块的hash值填入所述分片区块的区块头中,例如将最新主链区块的hash值填入图18的“最新主链区块Hash”字段中。这样,目标分片生成的目标分片区块中,不仅可以在区块体中填入主链发来的跨片交易中涉及的由该目标分片执行的操作,还可以在分片区块的区块头中锁定最新的主链区块的hash值。例如图18中所示,分片区块102的区块头中的最新主链区块hash字段中可以填入主链区块10004的hash值。分片区块102的区块体中,可以填入主链区块10003和10004中的跨片交易中需要由分片1执行的操作。基于相同的规则,区块101的区块头的最新主链区块Hash中,填入的是区块10002的hash值,从而,区块102的区块头的最新主链区块Hash中填入的区块10002的hash值,可以表示区块102的区块体中填入的包括主链区块10003和10004中的跨片交易中需要由分片1执行的操作。这样,便于根据分片区块的区块头中填入的主链区块来核实分片区块的区块体中是否填入了正确的主链区块的区块体中的跨分片交易的相关操作。
在一个实施例中,主链也可以发送主链区块的hash至分片,而不是将主链区块的区块头发送至分片。由于主链一般具有足够高的可信度,这样的方式可以降低分片的hash计算量。
区块hash一般可以唯一对应一个区块。考虑到区块号一般是连续的,也可以唯一对应一个区块,因此,可以在分片区块的区块头中填入最新主链区块的区块号,以替代最新主链区块hash,并可以起到基本相同的作用。在一个实施例中,主链也可以发送主链区块的区块号至分片。由于主链一般具有足够高的可信度,因此分片可以信任主链发来的主链区块号。
通过上述本申请的实施例,由于各个分片的区块体中填入了跨分片交易中涉及该分片的操作,这样,可以在当前分片中记录执行的跨分片交易的操作。
以下实施例介绍本申请一种锁定包含分片的区块链系统中跨片事务的区块链系统,该区块链系统中至少包括两个分片,不同分片中的节点存储不同的状态集合;所述区块链系统还包括主链;且,
主链根据主链区块中的跨片交易涉及的目标分片将所述主链区块的区块体中跨分片交易需要目标分片执行的操作发送至对应的目标分片;
接收到所述主链区块的目标分片在生成分片区块的过程中,将接收到的需要由该目标分片执行的操作填入所述分片区块的区块体中。
对于没有产生的分片发来的跨片交易,主链区块中的跨片交易操作中不包括相应行或者对应行为空。
主链还将所述主链区块体中各个操作的hash值按照树形结构计算得到的根的hash值填入主链区块的区块头的交易根hash中。
所述目标分片还在生成的区块头中由交易根hash锁定该目标分片的区块体中的原始交易列表。
所述接收到所述主链区块的目标分片在生成分片区块的过程中,还将主链区块的hash值/区块头填入所述分片区块的区块头中。
所述目标分片在生成分片区块的过程中将最新主链区块的hash值/区块号填入所述分片区块的区块头中。
主链区块的hash值由分片区块根据主链区块的区块头计算得到,或通过接收主链发送的主链区块hash得到。
所述不同分片中的节点存储不同的状态集合,包括:
不同分片中的节点存储不同的外部账户集合的状态;和/或,
不同分片中的节点存储不同合约账户状态集合;和/或,
不同分片中的节点存储不同合约账户集合的状态。
所述主链上生成区块的频率高于各个分片中生成区块的频率。
所述不同分片中的节点存储不同的外部账户集合的状态,包括:
不同分片中的节点执行创建和/或调用合约的交易而产生的与外部账户相关的状态并存储;和/或,
不同分片中的节点执行普通转账交易产生的外部账户的状态并存储。
以下实施例介绍本申请一种区块链主链,所述区块链主链是包含分片的区块链系统中的主链,所述分片用于存储状态的集合,且不同分片存储的状态的集合不同;
所述主链接收不同分片发来的跨片交易中需要由目标分片执行的操作;
所述主链生成主链区块的过程中,将需要由目标分片执行的操作填入所述主链区块的区块体中;
所述主链根据主链区块中的跨片交易涉及的目标分片将所述主链区块的区块体中跨分片交易需要目标分片执行的操作发送至对应的目标分片。
对于没有产生的分片发来的跨片交易,主链区块中的跨片交易操作中不包括相应行或者对应行为空。
所述主链将所述主链区块体中各个操作的hash值按照树形结构计算得到的根的hash值填入主链区块的区块头的交易根hash中。
所述不同分片中的节点存储不同的状态集合,包括:
不同分片中的节点存储不同的外部账户集合的状态;和/或,
不同分片中的节点存储不同合约账户状态集合;和/或,
不同分片中的节点存储不同合约账户集合的状态。
所述主链上生成区块的频率高于各个分片中生成区块的频率。
以下实施例介绍本申请一种区块链分片,所述区块链分片是包含主链的区块链系统中的一个分片,用于存储状态的集合,且存储的状态的集合不同于其它分片中的状态的集合;
所述区块链分片接收主链发送的需要由所述区块链分片执行跨分片交易相关的操作;
所述区块链分片生成分片区块的过程中,将接收到的需要由该区块链分片执行的操作填入所述分片区块的区块体中。
所述区块链分片还在生成的区块头中由交易根hash锁定该目标分片的区块体中的原始交易列表。
所述区块链分片在生成分片区块的过程中,还将主链区块的hash值/区块头填入所述分片区块的区块头中。
所述区块链分片在生成分片区块的过程中将最新主链区块的hash值/区块号填入所述分片区块的区块头中。
所述不同分片中的节点存储不同的状态集合,包括:
不同分片中的节点存储不同的外部账户集合的状态;和/或,
不同分片中的节点存储不同合约账户状态集合;和/或,
不同分片中的节点存储不同合约账户集合的状态。
以下实施例介绍本申请一种区块链节点,所述区块链节点归属于区块链系统中的主链,所述区块链系统中包含分片,所述分片用于存储状态的集合,且不同分片存储的状态的集合不同;
所述区块链节点接收不同分片发来的跨片交易中需要由目标分片执行的操作;
所述区块链节点生成主链区块的过程中,将需要由目标分片执行的操作填入所述主链区块的区块体中;
所述区块链节点根据主链区块中的跨片交易涉及的目标分片将所述主链区块的区块体中跨分片交易需要目标分片执行的操作发送至对应的目标分片。
对于没有产生的分片发来的跨片交易,主链区块中的跨片交易操作中不包括相应行或者对应行为空。
所述区块链节点将所述主链区块体中各个操作的hash值按照树形结构计算得到的根的hash值填入主链区块的区块头的交易根hash中。
所述不同分片中的节点存储不同的状态集合,包括:
不同分片中的节点存储不同的外部账户集合的状态;和/或,
不同分片中的节点存储不同合约账户状态集合;和/或,
不同分片中的节点存储不同合约账户集合的状态。
所述区块链主链节点上生成区块的频率高于各个分片中节点生成区块的频率。
以下实施例介绍本申请一种区块链节点,所述区块链节点归属于区块链系统中的一个分片,所述区块链分片是包含主链的区块链系统中的一个分片;区块链节点用于存储状态的集合,且存储的状态的集合不同于其它分片中节点存储的状态的集合;
所述区块链节点包括:
处理器;
存储器,其中存储有程序,其中在所述处理器执行所述程序时,执行如下内容:
所述区块链节点接收主链发送的需要由所述区块链分片执行跨分片交易相关的操作;
所述区块链节点生成分片区块的过程中,将接收到的需要由该区块链分片执行的操作填入所述分片区块的区块体中。
所述区块链节点还在生成的区块头中由交易根hash锁定该目标分片的区块体中的原始交易列表。
所述区块链节点在生成分片区块的过程中,还将主链区块的hash值/区块头填入所述分片区块的区块头中。
所述区块链节点在生成分片区块的过程中将最新主链区块的hash值/区块号填入所述分片区块的区块头中。
所述不同分片中的节点存储不同的状态集合,包括:
不同分片中的节点存储不同的外部账户集合的状态;和/或,
不同分片中的节点存储不同合约账户状态集合;和/或,
不同分片中的节点存储不同合约账户集合的状态。
在20世纪90年代,对于一个技术的改进可以很明显地区分是硬件上的改进(例如,对二极管、晶体管、开关等电路结构的改进)还是软件上的改进(对于方法流程的改进)。然而,随着技术的发展,当今的很多方法流程的改进已经可以视为硬件电路结构的直接改进。设计人员几乎都通过将改进的方法流程编程到硬件电路中来得到相应的硬件电路结构。因此,不能说一个方法流程的改进就不能用硬件实体模块来实现。例如,可编程逻辑器件(Programmable Logic Device, PLD)(例如现场可编程门阵列(Field ProgrammableGate Array,FPGA))就是这样一种集成电路,其逻辑功能由用户对器件编程来确定。由设计人员自行编程来把一个数字系统“集成”在一片PLD上,而不需要请芯片制造厂商来设计和制作专用的集成电路芯片。而且,如今,取代手工地制作集成电路芯片,这种编程也多半改用“逻辑编译器(logic compiler)”软件来实现,它与程序开发撰写时所用的软件编译器相类似,而要编译之前的原始代码也得用特定的编程语言来撰写,此称之为硬件描述语言(Hardware Description Language,HDL),而HDL也并非仅有一种,而是有许多种,如ABEL(Advanced Boolean Expression Language)、AHDL(Altera Hardware DescriptionLanguage)、Confluence、CUPL(Cornell University Programming Language)、HDCal、JHDL(Java Hardware Description Language)、Lava、Lola、MyHDL、PALASM、RHDL(RubyHardware Description Language)等,目前最普遍使用的是VHDL(Very-High-SpeedIntegrated Circuit Hardware Description Language)与Verilog。本领域技术人员也应该清楚,只需要将方法流程用上述几种硬件描述语言稍作逻辑编程并编程到集成电路中,就可以很容易得到实现该逻辑方法流程的硬件电路。
控制器可以按任何适当的方式实现,例如,控制器可以采取例如微处理器或处理器以及存储可由该(微)处理器执行的计算机可读程序代码(例如软件或固件)的计算机可读介质、逻辑门、开关、专用集成电路(Application Specific Integrated Circuit,ASIC)、可编程逻辑控制器和嵌入微控制器的形式,控制器的例子包括但不限于以下微控制器:ARC 625D、Atmel AT91SAM、Microchip PIC18F26K20 以及Silicone Labs C8051F320,存储器控制器还可以被实现为存储器的控制逻辑的一部分。本领域技术人员也知道,除了以纯计算机可读程序代码方式实现控制器以外,完全可以通过将方法步骤进行逻辑编程来使得控制器以逻辑门、开关、专用集成电路、可编程逻辑控制器和嵌入微控制器等的形式来实现相同功能。因此这种控制器可以被认为是一种硬件部件,而对其内包括的用于实现各种功能的装置也可以视为硬件部件内的结构。或者甚至,可以将用于实现各种功能的装置视为既可以是实现方法的软件模块又可以是硬件部件内的结构。
上述实施例阐明的系统、装置、模块或单元,具体可以由计算机芯片或实体实现,或者由具有某种功能的产品来实现。一种典型的实现设备为服务器系统。当然,本申请不排除随着未来计算机技术的发展,实现上述实施例功能的计算机例如可以为个人计算机、膝上型计算机、车载人机交互设备、蜂窝电话、相机电话、智能电话、个人数字助理、媒体播放器、导航设备、电子邮件设备、游戏控制台、平板计算机、可穿戴设备或者这些设备中的任何设备的组合。
虽然本说明书一个或多个实施例提供了如实施例或流程图所述的方法操作步骤,但基于常规或者无创造性的手段可以包括更多或者更少的操作步骤。实施例中列举的步骤顺序仅仅为众多步骤执行顺序中的一种方式,不代表唯一的执行顺序。在实际中的装置或终端产品执行时,可以按照实施例或者附图所示的方法顺序执行或者并行执行(例如并行处理器或者多线程处理的环境,甚至为分布式数据处理环境)。术语“包括”、“包含”或者其任何其他变体意在涵盖非排他性的包含,从而使得包括一系列要素的过程、方法、产品或者设备不仅包括那些要素,而且还包括没有明确列出的其他要素,或者是还包括为这种过程、方法、产品或者设备所固有的要素。在没有更多限制的情况下,并不排除在包括所述要素的过程、方法、产品或者设备中还存在另外的相同或等同要素。例如若使用到第一,第二等词语用来表示名称,而并不表示任何特定的顺序。
为了描述的方便,描述以上装置时以功能分为各种模块分别描述。当然,在实施本说明书一个或多个时可以把各模块的功能在同一个或多个软件和/或硬件中实现,也可以将实现同一功能的模块由多个子模块或子单元的组合实现等。以上所描述的装置实施例仅仅是示意性的,例如,所述单元的划分,仅仅为一种逻辑功能划分,实际实现时可以有另外的划分方式,例如多个单元或组件可以结合或者可以集成到另一个系统,或一些特征可以忽略,或不执行。另一点,所显示或讨论的相互之间的耦合或直接耦合或通信连接可以是通过一些接口,装置或单元的间接耦合或通信连接,可以是电性,机械或其它的形式。
本发明是参照根据本发明实施例的方法、装置(系统)、和计算机程序产品的流程图和/或方框图来描述的。应理解可由计算机程序指令实现流程图和/或方框图中的每一流程和/或方框、以及流程图和/或方框图中的流程和/或方框的结合。可提供这些计算机程序指令到通用计算机、专用计算机、嵌入式处理机或其他可编程数据处理设备的处理器以产生一个机器,使得通过计算机或其他可编程数据处理设备的处理器执行的指令产生用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的装置。
这些计算机程序指令也可存储在能引导计算机或其他可编程数据处理设备以特定方式工作的计算机可读存储器中,使得存储在该计算机可读存储器中的指令产生包括指令装置的制造品,该指令装置实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能。
这些计算机程序指令也可装载到计算机或其他可编程数据处理设备上,使得在计算机或其他可编程设备上执行一系列操作步骤以产生计算机实现的处理,从而在计算机或其他可编程设备上执行的指令提供用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的步骤。
在一个典型的配置中,计算设备包括一个或多个处理器(CPU)、输入/输出接口、网络接口和内存。
内存可能包括计算机可读介质中的非永久性存储器,随机存取存储器(RAM)和/或非易失性内存等形式,如只读存储器(ROM)或闪存(flash RAM)。内存是计算机可读介质的示例。
计算机可读介质包括永久性和非永久性、可移动和非可移动媒体可以由任何方法或技术来实现信息存储。信息可以是计算机可读指令、数据结构、程序的模块或其他数据。计算机的存储介质的例子包括,但不限于相变内存(PRAM)、静态随机存取存储器(SRAM)、动态随机存取存储器(DRAM)、其他类型的随机存取存储器(RAM)、只读存储器(ROM)、电可擦除可编程只读存储器(EEPROM)、快闪记忆体或其他内存技术、只读光盘只读存储器(CD-ROM)、数字多功能光盘(DVD)或其他光学存储、磁盒式磁带,磁带磁磁盘存储、石墨烯存储或其他磁性存储设备或任何其他非传输介质,可用于存储可以被计算设备访问的信息。按照本文中的界定,计算机可读介质不包括暂存电脑可读媒体(transitory media),如调制的数据信号和载波。
本领域技术人员应明白,本说明书一个或多个实施例可提供为方法、系统或计算机程序产品。因此,本说明书一个或多个实施例可采用完全硬件实施例、完全软件实施例或结合软件和硬件方面的实施例的形式。而且,本说明书一个或多个实施例可采用在一个或多个其中包含有计算机可用程序代码的计算机可用存储介质(包括但不限于磁盘存储器、CD-ROM、光学存储器等)上实施的计算机程序产品的形式。
本说明书一个或多个实施例可以在由计算机执行的计算机可执行指令的一般上下文中描述,例如程序模块。一般地,程序模块包括执行特定任务或实现特定抽象数据类型的例程、程序、对象、组件、数据结构等等。也可以在分布式计算环境中实践本本说明书一个或多个实施例,在这些分布式计算环境中,由通过通信网络而被连接的远程处理设备来执行任务。在分布式计算环境中,程序模块可以位于包括存储设备在内的本地和远程计算机存储介质中。
本说明书中的各个实施例均采用递进的方式描述,各个实施例之间相同相似的部分互相参见即可,每个实施例重点说明的都是与其他实施例的不同之处。尤其,对于系统实施例而言,由于其基本相似于方法实施例,所以描述的比较简单,相关之处参见方法实施例的部分说明即可。在本说明书的描述中,参考术语“一个实施例”、“一些实施例”、“示例”、“具体示例”、或“一些示例”等的描述意指结合该实施例或示例描述的具体特征、结构、材料或者特点包含于本说明书的至少一个实施例或示例中。在本说明书中,对上述术语的示意性表述不必须针对的是相同的实施例或示例。而且,描述的具体特征、结构、材料或者特点可以在任一个或多个实施例或示例中以合适的方式结合。此外,在不相互矛盾的情况下,本领域的技术人员可以将本说明书中描述的不同实施例或示例以及不同实施例或示例的特征进行结合和组合。
以上所述仅为本说明书一个或多个实施例的实施例而已,并不用于限制本本说明书一个或多个实施例。对于本领域技术人员来说,本说明书一个或多个实施例可以有各种更改和变化。凡在本说明书的精神和原理之内所作的任何修改、等同替换、改进等,均应包含在权利要求范围之内。