Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
133 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。
3 v! y) [# ^- Q$ ^  s" x2 }: }$ b( d) U( K1 `( n/ Q
Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。
  @2 S+ B& N* n- W/ g  |5 B8 r主侧链协同工作模型
- @# z( `8 v) u$ H& m- B3 {/ B0 Z
- W% C. X9 O7 H  d0 p7 y. D1 ^1、技术细节
& y$ k( B8 A& P1 F% h$ NPOW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。
$ _* S- }! W) ^! [& f4 M而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求
: H; L4 x3 F. C/ g" m(1)跨链模型架构( K. h' n  o& A
在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。
& k- z3 E: @  Z; Q4 y3 M, j$ Q& i(2)节点类型
' _- h: p" T& |1 T# h跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。9 l2 O8 ?) F8 S" q
(3)跨链交易流程1 t5 w: V6 |3 g5 ]% I2 H
主链到侧链
' D) b! ]3 ^! R主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链2 z# Z$ I  h8 |. [- h
侧链到主链( c8 u( d& l: n  T* U
侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。: F+ {; h) q3 q, h6 R
2、代码解析% c- T! Z3 {9 x6 |! {
跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。
2 k+ d9 u3 V% M(1)keeper启动% c0 Q  }9 Y8 i4 ^. d+ `( z
整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。3 o* K; E2 _2 a) }3 R% c
func (m *mainchainKeeper) Run() {
. E6 f2 @, ?3 \6 F5 ~2 F        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)) j, I$ Y. R7 p
        for ; true;
" F7 |  Q, S1 m3 @Run函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。" }/ j& m! {6 @* C- Q- W
(2)主侧链同步区块
- C5 Y* ^8 o( _# [0 |7 A# WRun函数会调用syncBlock函数同步区块。* `; p  i! o* N4 Z
func (m *mainchainKeeper) syncBlock() (bool, error) {
" E5 X& }: j  a        chain := &orm.Chain{Name: m.chainName}
5 k; H  U2 [1 o3 W2 L! c2 v        if err := m.db.Where(chain).First(chain).Error; err != nil {
" j# D8 R% G" @9 u                return false, errors.Wrap(err, "query chain"). l" s- V8 w6 |8 D; i
        }
! w. X4 {$ G' c. H" {        height, err := m.node.GetBlockCount()
' Q- d& j/ z" i6 J# ]+ V; d3 B        //..  ?/ y6 f) b* r4 X
        if height % Y0 s& \9 A* Y: f
这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。* Y" M7 C. p$ S7 q
height
! N# n- K  L" ^/ A$ G1 g主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。( k! S# i3 t8 n8 w1 n$ U
nextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)1 S: p* N) `1 d6 s# f1 v8 }+ V

9 v' h& B9 K0 U; ?这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。! i9 Y; I8 z5 p/ X) R4 r6 B
if nextBlock.PreviousBlockHash.String() != chain.BlockHash {+ \) z" G0 I$ {0 \3 X
    //..
0 [5 ]& r& g) w4 M& n2 `7 X, A( C}
6 ~+ O0 v3 H' g& h" g在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。
3 \5 f  P8 I7 v$ ^) f(3)区块处理
! }1 d) d+ F; k& WprocessBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。
* x3 }1 \; q# m- C7 Q# Ufunc (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {
6 T; ^' u( C+ a5 e$ ^+ g        if err := m.processIssuing(block.Transactions); err != nil {
& }# j& [2 s2 T4 m3 x                return err1 G; a2 }6 z* Y
        }
9 i8 @/ y. v/ A2 W        for i, tx := range block.Transactions {
5 M8 r. A& W  \$ K                if m.isDepositTx(tx) {
+ R: z& v7 v9 V" i                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {
6 ~- g  t# S3 M2 A. [% u                                return err9 C" U" I8 b2 @( c
                        }
  V( W8 k1 G; W% k- o4 l0 z" A- L                }7 R. d" v7 s2 T7 V& z* v
                if m.isWithdrawalTx(tx) {9 {0 w5 \' U0 _. g( I
                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {% o$ e1 p5 v2 D0 |  L8 ]2 o' m' C5 @
                                return err
7 s8 _- z" n7 Q$ j. @. e: d                        }
& m) c/ Q( N. s) Y$ i( \  q                }, D0 k" e- m0 |0 n. {
        }0 A! u+ R7 [% s
        return m.processChainInfo(chain, block)
& u& z' L* N% m( J}# {) Q# B# l, B* F/ ?( p
在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。
# ^! o# C4 i" Z% ^8 q6 Km.assetStore.Add(&orm.Asset{
; v: g/ I; O% y# n. h% B- L2 LAssetID:           assetID.String(),
6 N/ p, `& N  i8 O9 b5 I2 TIssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),
8 k" U% Y, x3 F( R; j* D3 dVMVersion:         inp.VMVersion,& e& d* y& G4 A: w  F
RawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),
3 N5 P* ~% ^5 E8 T})
# U8 ~2 `; X* z: i在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。
  b0 p" o$ r; o# kfunc (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {
8 v  R7 \7 x2 c8 g' Y5 a        for _, output := range tx.Outputs {
( n. T; D9 D0 L' z  }                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {2 ~- E! ~. G% R1 L5 W
                        return true
& I- s% c  b+ d7 k, e1 ^( l" E                }( s8 l: n, ?' T8 _- L/ x
        }
; n, E" s* k; b$ B, [+ L6 h        return false
/ v* s& Z% y3 P+ s}
! _0 \1 S" y- r, U. w9 V0 g7 ^func (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {
- _  k( T7 @/ o1 D        for _, input := range tx.Inputs {/ _; ^8 Z3 _  m
                if bytes.Equal(input.ControlProgram(), m.fedProg) {
& C& |; f( r9 P! Y                        return true& ^# l( v' l) h# o# l! e
                }0 S2 m: t( \. ~4 Q; @
        }5 Q9 Y& x& i* I9 B: q+ J2 V5 z
        return false& z4 d) X4 Q1 i; N  E8 i) S
}2 Y- X, ?4 `1 h6 V" k4 J
看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。5 m7 E  H+ a) X' m
type mainchainKeeper struct {; P! X2 m% v( |; L3 D5 {0 q
        cfg        *config.Chain
( E  U7 l3 }2 Q( q; ]        db         *gorm.DB
4 ?  Y5 `3 y; h' L2 z$ ]        node       *service.Node+ j7 w' [- l, d8 c0 Z
        chainName  string, i& }2 V- H9 {0 M) ]6 K/ I
        assetStore *database.AssetStore
- _6 ~: j, j- E: E        fedProg    []byte
0 u( Q. |) `- P}
& @4 D& k3 j4 k7 ?) L5 V(4)跨链交易(主链到侧链的deposit)处理5 f: o! }( r( h, f2 q3 C1 a) T$ S- m
这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。
) \- @5 R8 z/ D( i9 w. v# Cfunc (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {/ z  l# s3 O, g9 c6 P* N9 O: i3 P
        //..
5 |" H1 P3 z; o! z+ n6 P        rawTx, err := tx.MarshalText()
6 X/ @  Y2 L* D8 J, k8 Y* i4 x: ?        if err != nil {
' B6 p8 I; L# [3 P6 t) g                return err- c/ u9 S1 j' M6 K1 S7 O, l
        }2 U% R; I# N% p( v! B
        ormTx := &orm.CrossTransaction{
" W. O5 n3 k% q4 s              //..
4 o( q* w" H. z! y7 W        }& C2 H5 L1 _; t' w$ Q# L
        if err := m.db.Create(ormTx).Error; err != nil {' x$ b& {  P1 @- ?8 ^
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))- ~$ i4 ^8 r# a# K
        }& E2 x; t6 l$ `' S
        statusFail := txStatus.VerifyStatus[txIndex].StatusFail3 I: ~. e  T  s; X
        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)8 A: h: o. {. @
        if err != nil {$ y% y% Q2 D5 a6 U: L
                return err
, e1 }- M- K, b) c( h/ l' @( M        }
- J2 X3 Q  Y% s# |        for _, input := range crossChainInputs {9 h3 n/ m5 L" w! x1 ~
                if err := m.db.Create(input).Error; err != nil {
$ v2 i" Z8 J1 l8 J/ P                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))% X& M$ h# J5 V' U+ t" C  ?( q
                }
$ d; w# P* d1 n6 W( w; n9 I$ d        }6 t# [: q2 M" a$ F4 l
        return nil5 M6 N" t; a4 G. K6 [
}4 X! ^9 v% P5 w* D6 J" O/ k7 U) V
这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。
5 _+ V' Y* @# C2 L; d) R& z# q  I$ J1 m0 X; uormTx := &orm.CrossTransaction{' \6 A! Z6 S1 I) O8 v
                ChainID:              chain.ID,0 @0 o# I7 u( F% n# p: W+ k4 K
                SourceBlockHeight:    block.Height,
7 V; ]8 |4 R* v. V1 R                SourceBlockTimestamp: block.Timestamp,4 h- J2 X' w2 T
                SourceBlockHash:      blockHash.String(),) x1 I5 W" u+ P. U# n
                SourceTxIndex:        txIndex,
6 m2 ]  V* w8 D4 o0 K+ G. c$ [                SourceMuxID:          muxID.String(),8 H- N" @( }. Y. B/ k5 f
                SourceTxHash:         tx.ID.String(),& K% O. ]2 N( x0 }; W* x
                SourceRawTransaction: string(rawTx),: S' b8 ?) r* N) s# f4 E* ?& b7 p
                DestBlockHeight:      sql.NullInt64{Valid: false},
9 E+ }1 Z/ x1 f9 ]9 J7 Y8 T                DestBlockTimestamp:   sql.NullInt64{Valid: false},
! V. h" _* V; T9 `1 V' ~                DestBlockHash:        sql.NullString{Valid: false},
7 G7 K5 Z% O2 b5 K8 z                DestTxIndex:          sql.NullInt64{Valid: false},
) f% }3 J8 F1 q2 O8 _% J( M) w* e$ X                DestTxHash:           sql.NullString{Valid: false},% @4 S. n1 T  g$ a& u: ?
                Status:               common.CrossTxPendingStatus," P& I+ J) W* D* j8 l! M, _
        }
" Y' I7 t  I3 c' q创建这笔跨链交易后,它会将交易存入数据库中。8 ^- S$ B. ^3 c3 T% X4 G
if err := m.db.Create(ormTx).Error; err != nil {
! a' V$ X+ \4 I0 E) N                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
- t' D' i$ {- t' ~: p+ y2 s: W}
' S) z, }/ R- e. h- x. v在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。( ]. Y2 t! x6 k7 t- u8 X! O  H- E
func (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {" {; b4 y7 |( s6 |4 i
        //..
: [/ p! O/ q: W0 ^1 R0 u9 l1 o        switch {
# E6 Z8 B2 V7 g+ F! J6 b( {1 h9 H        case segwit.IsP2WPKHScript(prog):
& @% b! B. L# n1 P5 c; ^+ ]) G                //..1 ^( g' s" `# ?9 k
        case segwit.IsP2WSHScript(prog):; n# o2 y# o9 p# _/ O3 j7 f" G
                //..
0 g, E: ~6 V3 |; |- R) ~        }
1 R9 j: O7 w: I3 c5 B5 v! m: g& {        reqs := []*orm.CrossTransactionReq{}- U* \1 c8 ^5 w2 w% w7 h
        for i, rawOutput := range tx.Outputs {
* Y' v: C0 W9 K1 w0 C) Z7 f                //..5 i9 ?4 ~3 S4 U0 G' _
                req := &orm.CrossTransactionReq{8 G/ {# ]" E7 d- W
                        //..- n6 v3 W/ f4 O9 K
                }0 Y* M7 p9 z9 z6 b0 A
                reqs = append(reqs, req)
+ f1 N" x: a; y6 V1 Z        }
4 _- b, K; W. ^4 G5 k5 L5 n" F" l1 I        return reqs, nil
/ D" v% e  T. V! U1 f$ Y5 u9 [}6 a2 E: X9 B- y5 q8 y. n
很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。
. F; T" c% l% a4 U. q0 Q, O' \1 Mswitch {
( G$ c  e$ g* ?  }        case segwit.IsP2WPKHScript(prog):) @5 p% T2 i' x! M' r8 T
                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
+ m. v- Z! u- _, i                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)
9 g7 q: x; ~; q                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams); S5 C  v1 y, q- }! Z
                }
) I+ x5 P4 P3 g7 _/ |& @        case segwit.IsP2WSHScript(prog):  O$ D% J( E" Z: R- `+ z
                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {9 i, g% R: f% ^) o* y' s
                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)
+ Z/ b1 R6 C. }$ u. q( V                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)
$ ^. E4 W) {* B                }
' @& V+ n# t0 N8 \        }, Z/ w2 F& O6 ^- m, ]
在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。- R2 Z- q  Q; n/ F
req := &orm.CrossTransactionReq{
5 J7 v" K( j9 B   CrossTransactionID: crossTransactionID,
6 F& ^) D: d3 C6 B; q   SourcePos:          uint64(i),& e8 y9 g1 u$ e5 {; Q
   AssetID:            asset.ID,1 A+ j+ t/ i! X
   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount,
& e% o+ S2 u& U  v( c0 }# ^   Script:             script,; X2 z+ X# Y  N& e  n0 \
   FromAddress:        fromAddress,& c) D- a7 h0 c( O" @  \& R
   ToAddress:          toAddress,
- c- y2 ~( P0 \0 V: `) J   }* o! Z( o6 e+ m
创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。7 i" s3 U$ x# Z: H: F3 w
for _, input := range crossChainInputs {+ G; z5 C. ]8 b; c) f4 E" l/ h
                if err := m.db.Create(input).Error; err != nil {% S* ]3 f5 j" r: x, r4 o  {( M
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
* w% |  c" m5 j                }
  {/ g! x9 @! W' o+ q1 q0 g}
. K  \3 R  n; x3 ]$ q, O到这里,对主链到侧链的deposit已经处理完毕。
3 N5 X/ j& I$ n; a& `0 |) H. S(5)跨链交易(侧链到主链的withdraw)交易处理
1 }2 d; X+ j# X6 H* C这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。
3 D( J, w" z$ \3、跨链优缺点: F+ A6 ~9 M, w
优点! |+ ~7 _% ^8 u* L4 m
(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。
5 ^6 u& M$ m1 ^5 R1 e9 ~(2) 可以根据不同需求实现侧链,满足多种场景6 h0 e- W6 v/ A  d  y
缺点' ?5 ~0 O. r+ U( h0 W9 Q. L0 i
(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右
& N( S' X7 f6 s9 d# o(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大
0 g' l, ]2 }# M& k(3) 只支持资产跨链,不支持跨链智能合约调用
, p4 \6 P+ {* {# f  _+ s7 F. N4、跨链模型平行对比Cosmos  ?' m' J$ X! g" n% X1 h7 P7 Q3 b
可扩展性
' y( j$ y$ f# W' |% W$ h3 Xbystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。1 l9 F  |2 n$ V6 K# C$ r
代码开发进度
+ S1 i6 ?- ^9 ]1 V3 Hvapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。
+ x, D5 D1 p3 u) V9 C跨链模型0 I; z' s% E0 a7 G6 r
vapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。
4 p% D0 [; D5 C7 F0 I2 h% P  q, }5、参考建议3 D( d5 j8 D, X5 V* [# O* _, [' ?8 h
侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1