Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
215 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。: m- t9 O2 z. o6 H, Q
! _6 o& C, d( p1 N5 P
Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。9 x' e' M' s4 a% @3 ^
主侧链协同工作模型
) P) Z; a% l; i, w2 a- c' E& E: ~1 w  j+ c( z% {6 v
1、技术细节1 E# ~% s7 R. T1 a8 t% n- q
POW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。
; D$ b4 A8 I& U. I: V- ^: A& {3 T而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求
  F, E" w2 O9 j(1)跨链模型架构  Z! [( {! k1 X4 E; S1 c
在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。6 Y7 Y, j$ e( c) ^  }
(2)节点类型
% K% {+ p. h) L. L" Y( R$ N4 c跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。+ a+ l7 L3 z' E" q6 S
(3)跨链交易流程
5 O' n9 u; H; H) U' k  G主链到侧链
& C5 \* s& M4 g) S主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链
, j' F. T" U8 |7 [6 O8 P# u' j9 h侧链到主链
0 l; k+ }$ z' b$ b侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。
1 c6 y+ Z) Y9 e1 K( I% _# a2、代码解析
2 j, G# X9 L& X. t! g跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。
  M1 |' y( S* e0 R# R5 D% X, p7 x(1)keeper启动
3 L  d! I6 B1 D6 l整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。
( N) X; ~1 ~- [3 j4 o% Hfunc (m *mainchainKeeper) Run() {! A7 y9 d9 r# E- n, m' }5 Y
        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second); Z" Y& P( D. o$ L" O6 ?  E2 d1 p! f
        for ; true; + j. s: b# u. A( U/ e% F# ~8 m
Run函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。
& ]. e6 [+ l8 {- o(2)主侧链同步区块
  [8 _0 G# ?6 n7 m+ Z6 KRun函数会调用syncBlock函数同步区块。
* l* q: \# X7 K2 Ffunc (m *mainchainKeeper) syncBlock() (bool, error) {
& c8 g+ p. u! M7 m/ C        chain := &orm.Chain{Name: m.chainName}
" B' c2 d; D; p, F# D: A% G7 @6 ]        if err := m.db.Where(chain).First(chain).Error; err != nil {
& N/ }0 Z; w. r3 ]; g$ z                return false, errors.Wrap(err, "query chain")
, j; B- r1 c; i4 R6 d        }
! i' J5 X" O  b, |8 p$ Y6 ?% i        height, err := m.node.GetBlockCount()' o- _" O) D3 P8 B
        //..) W! B) N: H- t- k2 h5 C& E/ T% Q
        if height ! b) A+ R; ^5 C6 t$ B5 {# w
这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。
, z! P) N. `' o4 J$ wheight # L5 m+ x+ N( C
主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。
* O* w: U% Z1 D2 `7 t& h! Q8 i% cnextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)6 h* W' q5 p4 j5 r

" ?7 n) v' s0 Q2 T/ b, \这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。9 h. S, t5 @: Y
if nextBlock.PreviousBlockHash.String() != chain.BlockHash {
. N; @+ T$ E& I1 ]6 w; [    //..
9 U9 E( _2 H. Q4 _}/ X3 f$ g* i- [
在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。
! c$ a' J4 v! Q" X5 |3 }/ t8 a(3)区块处理
; x% r' S$ o, t& O( x/ ZprocessBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。+ ?$ j. O6 f# Q1 M9 L1 w
func (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {
: O1 z# }' r4 @% u/ i: J; j        if err := m.processIssuing(block.Transactions); err != nil {* \" A7 q$ I2 \
                return err) @# x/ t2 h& R
        }
1 f; |& N. M4 H. p% z& t        for i, tx := range block.Transactions {! x5 Z, g' ?/ [2 j, I9 D
                if m.isDepositTx(tx) {' F1 `* A" X* ~, {+ V/ W
                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {
- C+ |  B: h( Z' A2 |- @& `# B                                return err
$ g7 F! }- \/ I8 ~; ~4 w0 A                        }
  t4 V7 D) U* s& D                }
6 `- V( p; Z+ G7 H% e( E( ]                if m.isWithdrawalTx(tx) {' n1 E# `9 w' ]3 U
                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {0 |8 ^. Q& l7 H( ]$ n; w6 v
                                return err
/ z* q% D; D0 t& U5 s: M                        }
, q2 Z( }0 D9 O  O: p- Y9 \- n- q( n6 b; Z                }1 N0 k7 ~7 p4 {+ S/ R) O3 e2 V. j8 a, |
        }3 W6 J) O) V8 J
        return m.processChainInfo(chain, block)6 ^! g% J8 E& A  |( U
}
/ h$ }  H/ U- `0 B4 x/ F9 M在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。$ a6 ~+ y2 k! }. f5 B$ F
m.assetStore.Add(&orm.Asset{
; f5 Y  w! v& ]6 b) {+ W/ l; ~AssetID:           assetID.String(),  U) U  ?9 @5 y
IssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),( Z3 {* z9 e9 }& {- a
VMVersion:         inp.VMVersion,
2 D! D5 w$ r$ g; Z- zRawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),# i  b5 w1 T' t/ G1 F
})
! m& ?$ J+ B! J, R在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。
; h) Q/ {: m0 d# {$ A# xfunc (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {
+ T, u7 r! a! S0 O( V# ~$ k; C        for _, output := range tx.Outputs {
& ?% o% @1 H" {3 |- s' e7 |                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {, g  C: Z  \" ~3 @
                        return true
- F% _1 N; K0 A7 l5 f5 j                }, }' O+ q' e, C, R% E
        }* T* g2 [" k6 E' U% q6 _  V
        return false
, Z2 u' _) M$ \8 r/ G7 [}$ a, o( W# P  b, v5 S- t
func (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {8 Z3 P! Y& [" n: @! J
        for _, input := range tx.Inputs {
8 ^+ x0 v! G( C% D% ^+ e9 a2 c                if bytes.Equal(input.ControlProgram(), m.fedProg) {! P! v/ G+ y  z- \& x; Y2 y9 g8 E
                        return true
/ ~0 T" G6 k: S7 U! e( E; [                }
& b/ B4 w. M4 v) u: Q        }
/ a5 H1 ~  {7 k        return false
' f- l; |7 u; u3 Q/ H: i+ u}+ h( V. |& U( o6 n8 R+ T0 _
看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。$ B. x( d4 G4 x6 O2 N9 g2 _8 G7 ]! m
type mainchainKeeper struct {9 G, s, ?& C* ]2 e' Q0 u6 z6 D
        cfg        *config.Chain" g" {+ |. B0 v8 l* Y# K6 l2 L  {9 ]
        db         *gorm.DB& V# n; ^, Q. A; v
        node       *service.Node
; W4 T: O7 w( f" B' k, e        chainName  string
* ~! q. v( ^& X. @( \6 ~        assetStore *database.AssetStore
- z2 d2 x/ [9 k" I& P        fedProg    []byte
* Q$ U: u* g1 X9 s" G0 o}
4 j  n* Q$ [7 p$ ^(4)跨链交易(主链到侧链的deposit)处理
3 Y- n$ @% ~' @  T4 N" B0 A这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。# |1 @0 h( j* q2 B) e) T3 o% l6 [' X
func (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {4 _# t- E) p5 @1 B% P% U! j  D6 }
        //..- R% S& M0 u& G( N
        rawTx, err := tx.MarshalText()
: t. `( F4 s( r8 i. Z9 G        if err != nil {  E# H0 _  N5 U+ g4 m8 M
                return err
9 a8 ]5 H5 W& H2 {6 `        }2 X! y: _/ l; f2 X; P6 [
        ormTx := &orm.CrossTransaction{6 a8 h- d5 F+ S; r& e7 g
              //..
  M3 N- W6 J7 q. C        }+ l+ Z5 l7 m- l
        if err := m.db.Create(ormTx).Error; err != nil {
; R  ]1 E5 \5 w! g: ^) z                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
: T! Y9 ~* ^) r' [        }. Z" ~5 y8 |* X% S7 u
        statusFail := txStatus.VerifyStatus[txIndex].StatusFail
" V# @1 ~) C4 G+ y, J+ l        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)
# a3 A' I/ z6 {2 K        if err != nil {
+ p9 ]9 I: ?1 s, x( ]2 X                return err. Y0 K* t$ W3 U" X. S
        }7 e0 @6 `% \2 O% n6 G/ n4 v! N
        for _, input := range crossChainInputs {
% Y) `: [4 D8 @9 p8 s. G' \                if err := m.db.Create(input).Error; err != nil {$ `) f% U! V0 v; z
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
) n4 M5 {, C( i* B3 g8 T; _6 l* |/ Z) l                }" N$ B9 h5 l& M# \% w/ x
        }
; |  Z+ R* h( V, u1 C        return nil0 r3 b3 S' Q* z, a1 B- }4 B! O
}
' g7 c: Q4 n, W! W% s这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。
9 ^2 g+ V6 h4 c% X0 y  `- zormTx := &orm.CrossTransaction{9 k3 T0 W! l  g1 O" O1 M3 g( ^
                ChainID:              chain.ID,
! i2 T# b0 B* W: ]! P. }! K! O                SourceBlockHeight:    block.Height,( ?) P* L% Q1 _! t5 n! s  M2 X
                SourceBlockTimestamp: block.Timestamp,, L4 K( a% n& p! Y: i
                SourceBlockHash:      blockHash.String(),; l3 k$ \) Y8 n% R6 ]! ~. S2 y
                SourceTxIndex:        txIndex,
" s4 D) v. |& I* I4 V+ ~+ i                SourceMuxID:          muxID.String(),
4 E& A- W" V) r" f                SourceTxHash:         tx.ID.String(),0 Q7 b6 p+ ?+ ?/ @- K3 U/ w2 h
                SourceRawTransaction: string(rawTx),
( {- ?% B# Q% `8 o3 @3 {                DestBlockHeight:      sql.NullInt64{Valid: false},
) O5 a; j) O# v                DestBlockTimestamp:   sql.NullInt64{Valid: false},+ M6 ]: `" C: B
                DestBlockHash:        sql.NullString{Valid: false},/ m6 d& n% E8 |
                DestTxIndex:          sql.NullInt64{Valid: false},
7 |* y. L/ l' s3 I" w! q                DestTxHash:           sql.NullString{Valid: false},$ ^0 ?+ t* y. U+ Y: Z
                Status:               common.CrossTxPendingStatus,( s0 ]* w" L. F3 @, z( K0 v3 A
        }; [/ y, M7 O7 A. m' H
创建这笔跨链交易后,它会将交易存入数据库中。
2 f7 l; x1 C8 Qif err := m.db.Create(ormTx).Error; err != nil {# L1 m. V& |' K; R; l
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
/ l! q( [9 c) _- R. [}
; a! F- {2 D# \- P' I, ~在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。
% ~2 v! Z7 P( g" F; f6 J# Bfunc (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {& I: N6 y) ~7 }3 f% p. W
        //... j5 l( F) Y7 K( u8 ^  R
        switch {) s/ q3 P6 ?, w( b4 `% H
        case segwit.IsP2WPKHScript(prog):
+ b- }( P$ ?" x( e                //..
2 O! f5 ]( L, L' C# L) J% A' z        case segwit.IsP2WSHScript(prog):
- ?) {# _# D7 q                //..
5 n" C# D+ X& N3 K2 _3 X5 ~3 a& G        }& Y( o, a1 q9 K9 @2 H5 U' w! N
        reqs := []*orm.CrossTransactionReq{}$ H( k: n8 c) B; `
        for i, rawOutput := range tx.Outputs {- F$ X1 ]1 B; ^! D8 _) Q: b
                //..% P6 j+ L# s1 }+ f3 P2 Q; w
                req := &orm.CrossTransactionReq{6 ^" h+ J. T% z/ E  z3 s, Z" m
                        //..
0 i# k% h6 k& }8 {% t, w                }
- p5 }( M3 U/ c& H                reqs = append(reqs, req)7 S1 O1 k; E/ D/ S. V
        }
8 f8 L$ e$ l4 R6 x. H2 Z        return reqs, nil
' r( \% r4 x8 N. J- B) K' r9 {% I: O}
- X# ?( b# m0 a2 {. X/ L4 p, `很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。1 C4 U% H8 |. i  r4 V8 C4 ?4 U
switch {
7 H' d0 Q6 z# F" S' o3 x' G        case segwit.IsP2WPKHScript(prog):/ x. ]" L& V; t% g4 I  O8 t3 c5 k
                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {6 c1 V6 K+ o9 h" ^) d8 ?3 Y
                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)
8 |4 ]! p( h& S, F& Q                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams)
# z3 d- ]9 @1 i                }: s; t+ _; V) N& G+ j( c# F) X
        case segwit.IsP2WSHScript(prog):. @" r" X0 @9 R# n; T  S( H! f
                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {6 R/ o2 K3 Q, R; u& ]2 t8 Q
                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)' \  L0 u( b+ `3 o9 G: F: r
                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams); \" p6 d9 _: G. n
                }
; }; p3 K8 W9 m        }
- u. q) N$ K# x+ N7 B% [" v2 j6 G在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。
7 I1 ?) w& `; t$ F& I  creq := &orm.CrossTransactionReq{
. I5 c* l: F. u, P8 a$ E7 V   CrossTransactionID: crossTransactionID,' q  z* q0 Q) m8 f( p  _/ ]
   SourcePos:          uint64(i),
$ c% F$ d: h& N; l* a' Q7 m   AssetID:            asset.ID,3 t6 F! g8 |, W4 p% e, x
   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount," W3 l2 ~! D; j# b7 k  Q
   Script:             script,8 _' e+ n& C; c& j
   FromAddress:        fromAddress,
  T; _( J( Q. v4 f   ToAddress:          toAddress,) E9 Q+ c3 V0 ^: B* y
   }
! }* ~& N* P$ c5 W7 f4 Y, K& u, x创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。
# N1 B( H% Q: @% b0 }1 N$ j0 N! ~for _, input := range crossChainInputs {
2 p9 p- o/ j5 k' X* ~1 A" H                if err := m.db.Create(input).Error; err != nil {% @) D( S- a, c0 ~
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))7 }$ S6 M! }9 V0 \6 ]. J5 H
                }+ z9 a, Q. U6 {2 _4 Y
}
9 P  E1 g% s9 F. r# b8 B9 z+ W3 a到这里,对主链到侧链的deposit已经处理完毕。
# n8 v( k) \5 \. h(5)跨链交易(侧链到主链的withdraw)交易处理
/ d0 N4 }' E# T这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。
# K; a8 q4 |. J: y4 `1 O3、跨链优缺点7 ^* C- U6 c/ \
优点4 q- u9 a" K. b9 t: D* V) z5 i& T
(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。! D% [5 S; g4 e
(2) 可以根据不同需求实现侧链,满足多种场景/ }, u( c* `7 w  N3 A
缺点+ s5 _) j" F  d9 w! |/ N; u
(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右
  H% I( m; d. i; J5 I6 Z(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大
# o! h" ]# t/ b# ?! ?(3) 只支持资产跨链,不支持跨链智能合约调用5 A3 e/ ^7 r& S/ V+ j5 O
4、跨链模型平行对比Cosmos* Z3 p+ g5 G8 `, T
可扩展性) G4 Z- T8 ?" g# k, G* `, a
bystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。
* y: S/ q( ]/ V( C代码开发进度
2 l! L! [' D4 X' T4 q7 I* x& T7 Qvapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。8 t/ F4 U9 w" }
跨链模型
+ @# R6 }8 S7 K  G/ mvapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。  K0 ]' \& K  _. @6 z; M6 N& d
5、参考建议
, c, a7 r8 r1 H0 y2 V侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1