Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文
stateDB用来存储合约状态及账户余额,和indexDB类似,底层存储通过levelDB的kv存储来实现。和indexDB不同的是stateDB为了能够支持快速的状态回滚操作,实现了多版本,每个版本的kv数据会关联状态对应的快照高度,这样当快照回滚的时候,可以非常快速的恢复到目标高度的状态。
! W- K) [, L: y+ V" z' m4 `% t; I6 {  W7 ^' w9 Y
1.key设计  R  O1 K. u7 H$ _0 d
不管是账户余额还是合约都有唯一的地址,因此可以以地址为key来做空间划分,对于同一个地址的访问更容易实现更高的读写效率。另外为了区分不同数据类型,在地址的前面会有一个字节用来标记key对应的是账户余额还是合约状态,以及其他预定义的数据类型。
. H% z- ~! f! m; v" s& d+ Y# _2 k# n+ E. J9 _! O0 D9 f  ?
stateDB key的具体实现如上图示; s3 m# F8 |$ W0 Z8 L. P
key type:key的类型,用来区分账户余额,合约状态,账户余额历史,合约状态历史等5 H& P0 |* |# r7 G' A4 }4 [
address:状态所属的普通地址或合约地址3 ~& Y, |0 `0 M* M/ X3 n3 g
user key:对除了账户余额外的其他key type有效
1 b% K1 p1 v5 e* ^7 j; @$ X. rversion/sb height:通过快照高度来区分不同版本的状态/ m- y5 q/ g, V( m
6 Q$ J0 B- N* n! T. r" j0 W$ {
2.高度回滚2 l- ]6 K  G! L7 Z6 v
因为stateDB支持多版本的数据,因此可以实现对历史数据的遍历,这里只保留一个高度窗口内的多个数据版本,满足回滚的需求,同时也能避免数据过度膨胀。
9 k, o1 T% h9 Y- L8 |9 e由于只存储了历史快照数据,没有存储用户在两次快照之间的数据变动的细节信息,所以假如没有引入其他的机制,在数据回滚时,只能回滚到数据的某个历史快照状态,无法回滚到两个快照之间的某个细节状态。举个例子,假如在快照块高度为10000时,用户A1拥有数据k1=v1,在快照块高度为10001时,用户A1的数据变更为k1=v3,假设在快照高度为10000之后,k1的值变换了两次,从v1变化到了v3(v1->v2->v3),这表明在快照块10000与10001之间,用户A1产生了多于1个account block(一个account block会导致一个用户的数据集合发生原子变更),而stateDB只记录了快照块高度为10000和快照块高度为10001是用户A1的两个版本的数据,不会记录两个快照之间的account block产生的数据变动的细节信息,因而在发生数据回滚时,只能回滚到某个历史快照的数据状态。为了解决这个问题,引入了state redo机制,state redo中记录了最近写入的account block产生的数据变化的细节信息,那么在发生较近的数据回滚时,可以回滚到某个account block出现后的数据版本。但是如果发生较远的数据回滚时(如回滚了5000个快照块,实践中这样回滚的概率非常小),state redo机制就不起作用了,启动兜底方案,即只回滚到历史的快照数据版本,同时回滚这个快照块之后的所有account block。3 r4 k4 ^) ]' b/ n& h' m

6 }: ~" j8 u% u0 u8 [& M9 O' F1 m* Z3.缓存7 [+ S! x, u: q6 ?3 {) D! s
合约的更新操作并不会直接写入底层存储,而是会把操作本身依序记录在内存的unsaved数据结构,待合约执行成功后,通过redo操作记录写入stateDB,这个过程和accountBlock写入blockDB是作为一个整体进行操作的。
% B* N. T% U0 n8 G' w6 g* astateDB为最近读写入的账户余额、内置合约的状态及外置合约的元数据这些常用的数据建立了缓存,方便进行快速的读取。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

一身似水厝 初中生
  • 粉丝

    0

  • 关注

    0

  • 主题

    23