Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
137 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。
% s0 z  I+ n* F: Q2 T3 e" n! @' r, T( c: t" l# b0 O
Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。
* t5 a1 N5 h# J' I7 B' l1 R5 W主侧链协同工作模型
" O8 y, s( U, |& k0 B! w& q4 N
! Z) r" L4 A0 B$ h1、技术细节, Z4 j) q9 k) S3 D- U, S
POW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。
; ?$ J4 x2 Y6 K" C3 W而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求
: e7 W# ^' D' @7 ?8 r(1)跨链模型架构- ^. O* ?4 {% p. O4 @. D
在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。
. O  b/ n# J* q. D; j" `: `(2)节点类型* n: i. y! @& s: o. L" m& F& ~
跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。! q4 N3 d, l/ d* `1 [& K9 |
(3)跨链交易流程) R) f- V( ^' @/ k  g7 J; N/ L
主链到侧链
7 E6 t; z: I4 s% j( D主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链: R4 f1 B  g( S6 g
侧链到主链5 d: M& y, Z! z- B# j
侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。1 Q4 L7 d2 {$ w/ H" ]2 }. }
2、代码解析
+ ~- |# r2 o+ r跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。) v$ M5 |# M' H1 L. ^
(1)keeper启动8 M( x+ ~9 V2 u9 P* G$ Q: t. d/ V
整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。( u& i' a* j: x, i. \3 z
func (m *mainchainKeeper) Run() {4 s4 i1 V+ o2 v! d
        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)
* d& P# U+ Y+ Q: q7 ?        for ; true; ! U  z7 ^& w0 ?& |
Run函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。
+ ^" F  S! p6 m) j6 A8 t(2)主侧链同步区块1 R% ~, f$ W; t) q' f% f5 q9 K. @
Run函数会调用syncBlock函数同步区块。
8 X, S( O- F& p6 e/ U. g1 wfunc (m *mainchainKeeper) syncBlock() (bool, error) {! n2 |2 a' y6 F8 }
        chain := &orm.Chain{Name: m.chainName}# m+ S; o4 U( V7 Y
        if err := m.db.Where(chain).First(chain).Error; err != nil {' }3 u/ q" B* u2 A; Z
                return false, errors.Wrap(err, "query chain")
% O: f" e2 K7 ~4 W% g1 Y' x        }2 N; J5 n0 u! I' n  _
        height, err := m.node.GetBlockCount()) |3 m4 r, {6 `6 Z5 z
        //.." e$ Z# M0 Z+ m1 c& v
        if height ; i: G6 u% w/ F% ~# [
这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。6 |9 D" Q* y+ h4 L0 X
height
, e7 G0 W5 r) z. e: P7 h主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。
0 ^# }/ c0 H6 k6 C' D4 {nextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)7 P% [; v+ G, D7 M, `$ p7 z

2 k  [  ]  \. I% V; H这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。
; ^' k9 n( ]: g$ N1 xif nextBlock.PreviousBlockHash.String() != chain.BlockHash {  c# i0 Y) w0 A* n( _
    //..' ]9 g% o1 h5 c' u/ e
}
# f! N7 @5 X2 X( L* d  Q在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。
  c% p+ [" x& \; u# y/ m(3)区块处理
" u% I0 I/ F. x% v8 R- i/ qprocessBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。5 I+ c" Y3 X7 ]- u3 K, t
func (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {
  e' m! {' w3 L; z) m" _3 d  f4 S        if err := m.processIssuing(block.Transactions); err != nil {
1 t' L: |, H; y7 x  K                return err
6 J2 D0 a  V( o" H  ?& d        }
" d! S0 n+ ?2 b        for i, tx := range block.Transactions {' s* K$ g1 N4 I& g8 q
                if m.isDepositTx(tx) {- D, `8 O4 ]9 @7 z' a
                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {
: n4 P& b3 j9 u9 T! O! {0 K                                return err, ?0 R& ^0 l0 C1 q- C. q& O3 `6 m. M
                        }
2 M% j9 d% H* H! v# i                }
3 g* b# i% v- x                if m.isWithdrawalTx(tx) {3 ~4 `9 f* s/ S3 h- g7 D. g
                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {5 `; X$ H) L" T, j) M% z" N
                                return err- j- {) H5 R6 O
                        }7 F5 ]/ O- D( M; a9 Z8 U2 x# x
                }
0 M$ W2 T7 C1 b2 N2 ~2 v7 f. w! _        }
  \% c* M- z7 Q* I7 j: n6 R% D& Y        return m.processChainInfo(chain, block)
! z8 P0 t' |8 ]( D/ X' I/ ^}" B0 e/ O4 x, Q0 ]3 J  S
在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。
1 \3 F; u& m1 D4 `/ S4 om.assetStore.Add(&orm.Asset{! O/ F6 z6 R' _* C' @* e. F
AssetID:           assetID.String(),
7 ^' ~. _2 p8 a* v5 Y+ f" q6 bIssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),
4 ], _3 K7 |( D( D4 @' J& JVMVersion:         inp.VMVersion,
& u) H: z. I' |/ u! a+ D  yRawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),
; p0 O% p! p& k5 Z; S1 I! `" x})7 N9 Z( q& F: ]7 L. @0 X
在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。
: |6 r' W# a% v/ B5 X1 zfunc (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {( O, D1 V( `* Y' \, @/ J
        for _, output := range tx.Outputs {: X# v8 ~' p3 m
                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {
; x1 Q9 |2 b  M4 X' U% T& c                        return true
/ P+ v+ ~! R& V: m$ |                }5 q4 W6 U% R7 p4 o( Z: u6 o9 J
        }5 Y/ \6 _' p" N" `9 s. b
        return false
) _3 T' y/ j' k% p/ i}5 R/ {- x* j2 s$ `* \. a
func (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {) }/ B6 u( g, o2 ~$ h0 |
        for _, input := range tx.Inputs {
% E$ W6 q' T5 R  w! b                if bytes.Equal(input.ControlProgram(), m.fedProg) {; ~* }. p, L2 @9 ]1 j
                        return true
0 O. C2 m8 B$ c2 s% H& I* C: f                }4 Q* o, T' }9 Q1 r/ d& k! w5 z. \7 N
        }% t! f  |1 ~( u# [
        return false% y5 |  p2 D$ q* x% d4 @
}' u8 z  L% F: N$ R/ [. x. w
看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。
/ C& |. O7 Y1 X! g6 [/ a" {' n8 v; Ftype mainchainKeeper struct {3 M4 e# \+ {8 Z: C
        cfg        *config.Chain* ^' p5 l$ f8 q0 q% z! q6 z
        db         *gorm.DB0 R% k8 B1 p+ y8 W3 h
        node       *service.Node
$ w+ P6 c- a( r- d% r1 w+ e8 O        chainName  string8 E4 k. ]& v& f; i# C9 }( Z" L
        assetStore *database.AssetStore
3 K9 k; w& G, x: w. U' k        fedProg    []byte
! H8 D7 H8 R2 s8 B; y  N}
3 c2 Z' W! j, U( m) e(4)跨链交易(主链到侧链的deposit)处理, }+ ~8 U. _4 d! R% Q. |* k% y) G( H% A- m
这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。
+ _" J4 X  L8 I, Wfunc (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {: F. x+ F' C" N5 ^( k5 j
        //..
! X5 R) i( I0 A/ K9 Y& y- V% }        rawTx, err := tx.MarshalText()
7 p% `4 b$ R$ o. T6 }, t        if err != nil {
* B8 i$ m$ |) \. R# G- l                return err
$ J7 k' e) _0 h( h; S$ Y4 M        }  R: D: ^2 g9 U- W
        ormTx := &orm.CrossTransaction{9 u. w; M- q3 ^  B. P; V4 j' e
              //..
* o2 B- R5 _  z7 o$ w  U        }
; |' y6 g2 w+ z- a/ s  L, u6 ?. S6 A        if err := m.db.Create(ormTx).Error; err != nil {" R, v9 K/ f% f+ J; H( f
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
$ p% Y2 I2 [$ V" O9 X- ^% L( V. Q        }4 A. n, y1 W+ A" y9 f$ S- Y
        statusFail := txStatus.VerifyStatus[txIndex].StatusFail# G: B2 w6 E! h- f) s& b( ?
        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)
- k8 M* h# u- d# M- }6 |" c7 `, D( N        if err != nil {5 @. e$ `9 G+ f* G+ e: I, T. L
                return err8 w4 K! q$ g$ n) F) k: X
        }: }2 ?8 N, }' b# `3 _: \
        for _, input := range crossChainInputs {3 v0 Z, f. Z) P9 S$ N5 Y7 u
                if err := m.db.Create(input).Error; err != nil {
) S. I8 Q6 F% |$ K2 L" o; b! ^                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))9 _2 ^# \0 l' c% F
                }
8 C+ ~( V" V0 D1 g$ M5 e        }7 O$ L# d- @' t" y
        return nil
/ r7 D4 d9 N/ z) G. y7 u, @: Q}9 n$ J' B2 K* E6 b7 l! T
这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。
, U) K0 f  m9 T. F+ w0 _+ wormTx := &orm.CrossTransaction{
' R" a7 i  |" ~3 M" Y                ChainID:              chain.ID,
0 b. o4 }# E  ^+ F. V3 R                SourceBlockHeight:    block.Height,
0 _% Y, q, U; h" F7 ~) }: P# C                SourceBlockTimestamp: block.Timestamp,7 }4 K9 e% g" K$ R# f* ?( g: H& j
                SourceBlockHash:      blockHash.String(),' ^: t- x( E, O" q4 c/ }+ ?, L- {% S; T
                SourceTxIndex:        txIndex,6 v7 ?) f8 K! l, L  m: f7 T
                SourceMuxID:          muxID.String(),
2 k; |9 G2 \& D6 @                SourceTxHash:         tx.ID.String(),
. j& {7 Z7 s% M/ C2 V                SourceRawTransaction: string(rawTx),2 K! R) F! u9 t1 r- i( p3 }
                DestBlockHeight:      sql.NullInt64{Valid: false},# I7 a. \, U. {: s  e5 S
                DestBlockTimestamp:   sql.NullInt64{Valid: false},$ H& u0 W9 f" G$ }
                DestBlockHash:        sql.NullString{Valid: false},
9 @4 C) H8 r" P1 V' r                DestTxIndex:          sql.NullInt64{Valid: false},; a1 M. R- F) s% M/ `
                DestTxHash:           sql.NullString{Valid: false},9 _; q: |1 L% Q
                Status:               common.CrossTxPendingStatus,+ _+ N& U2 Z. ^% h
        }! A+ _- W. g7 h0 T* ~! D
创建这笔跨链交易后,它会将交易存入数据库中。3 U8 E: H0 a0 Y' J) n
if err := m.db.Create(ormTx).Error; err != nil {& _8 u; |8 s# a' @  {
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))( x$ d4 R* u4 a: n3 t  _3 ]
}+ F' i3 i7 t* ~5 U
在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。
1 m8 x% V( i" T" t3 G& G. nfunc (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {, c& _) g. S- V0 @( d2 B
        //../ X3 [. v( k: b3 v2 f
        switch {9 N* t2 L' M6 T3 M% M* C
        case segwit.IsP2WPKHScript(prog):( }1 Z  s6 Q5 R# s( R6 `
                //..
9 r* Q7 C: t6 R; Z9 Y" \        case segwit.IsP2WSHScript(prog):
3 H, Q( V1 Z* _! ~                //..8 i3 D; X" W6 N8 x3 a8 A
        }  @8 M& \. A8 l- j, w
        reqs := []*orm.CrossTransactionReq{}7 h: L" c1 `0 d* G8 W
        for i, rawOutput := range tx.Outputs {5 f0 ]7 a& E5 v) a0 w: s* a
                //..
8 c( r7 _9 Y, O6 [. C# Z                req := &orm.CrossTransactionReq{
2 d6 J# _! S) A. T6 u                        //..6 w' r, H' e, `
                }- ^; T8 m; X8 j; c6 g! h
                reqs = append(reqs, req)( l0 _# Q( K# ]. J- V0 ^8 l
        }& O5 I4 K6 k/ B
        return reqs, nil
5 P9 B/ ~6 }  ~; N# C}& R/ T- q" h: q8 T. C
很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。
5 O0 c! F) K9 g% U/ L, i9 nswitch {, \2 D& S8 H8 _" ?# p- O- N# L
        case segwit.IsP2WPKHScript(prog):
6 c3 I3 D5 R& V  k; b9 ?- L& O1 K3 _                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
0 k/ K( l+ P- V8 h6 P  i: \2 J1 {6 |. D                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)
& u& G, V" y- a) L$ k. D                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams)
( c, @$ m5 g. q$ e& z2 z' M                }4 K: k% d/ ]8 a  M7 X
        case segwit.IsP2WSHScript(prog):
/ Q/ L9 D& X" S6 D7 q; k1 J                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {) ^' C0 N0 J! j# ]* U' p0 l
                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)1 v' I4 d" w; l: F# A
                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)
1 u/ G. p: [6 v# A; T0 ?                }
/ a5 H5 N8 z7 M& z        }+ y9 b) t) d4 a1 a9 |; [; Z
在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。9 X5 b, [7 F& e2 m8 n
req := &orm.CrossTransactionReq{  i, z, V5 y0 l0 B2 u  E1 A
   CrossTransactionID: crossTransactionID,; i5 O- ^9 o# M$ O
   SourcePos:          uint64(i),
5 O+ K6 Q( n: Z: \% K   AssetID:            asset.ID,2 @" A/ i5 P0 k. V7 _! c& u% C5 h" O
   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount,
, p# v  k" R3 W# X   Script:             script,
8 D7 ^, M# x$ o6 G! ]4 ?+ l- j   FromAddress:        fromAddress,1 G1 T, j% H$ C  S: Z4 b* p" _, m
   ToAddress:          toAddress,( z8 M* Z4 J" S% y6 Q9 }& g6 m
   }
, X) \" Q0 p$ |4 y8 ]7 k7 M* w! t创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。6 Q% |) \* D# l$ ~
for _, input := range crossChainInputs {+ F5 U* k, L- p" k0 |# i% I; t
                if err := m.db.Create(input).Error; err != nil {
- u+ x5 u: S& _, [                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))* R0 n* V/ K5 {4 V6 i
                }7 ]  ^( [! |) b) p9 \2 Y
}
" Y+ J; Q* q! a# Z到这里,对主链到侧链的deposit已经处理完毕。
2 C- b: V+ L1 ^7 x5 K(5)跨链交易(侧链到主链的withdraw)交易处理
+ D4 V" l2 ^3 u3 a* y这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。
' x. o& j% _1 x% m3、跨链优缺点) I2 s, s7 G1 R2 y* Q/ [
优点
( |) v5 f7 \; R- v(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。* @/ T( v( M( {. d/ N. F
(2) 可以根据不同需求实现侧链,满足多种场景* C9 d  {" c( o0 z
缺点
- k! S& L+ |8 r- o(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右1 \, q' M( w% S8 J2 D& a# l" A! N
(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大
- s8 w, j9 m( I2 y6 A(3) 只支持资产跨链,不支持跨链智能合约调用
, Q3 Q8 n0 \3 [: r; s6 _4、跨链模型平行对比Cosmos* O# \% N* }+ V3 C
可扩展性
) B/ P* R& \5 S& T& Z1 t* E9 bbystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。
) ?/ j) E% N5 t! z- H代码开发进度
" `" L8 q! W6 i" X1 f1 tvapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。; Z) P- J: {( l
跨链模型9 F" |% R7 v  X
vapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。3 a) L0 a9 R2 G& V) @
5、参考建议
3 r0 ^' H/ f* _7 {! b侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1