Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
161 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。
9 R) S3 \( X8 ^" r* |- n; l) @3 u( [3 n& ?# t  ~
Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。
- V6 a$ z9 g  U# C  l0 _主侧链协同工作模型
0 b( Z* l: j) H1 R# I& s( w0 l- p# Z7 O1 c
1、技术细节0 D; m( e9 r$ Y. o/ l1 z
POW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。  F( X6 i6 e2 Z6 k  L. R# ~
而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求" x$ Y+ n9 b) ^/ }
(1)跨链模型架构
; d$ ?) R3 V; o# _$ g1 F在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。7 G0 U1 N; S3 p, P% p7 u' `
(2)节点类型
6 K8 |8 O7 a  \( S4 Z跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。
2 a% l5 [" Z6 W5 G& w) _(3)跨链交易流程7 I0 j% f8 ]+ r; f. ?9 G9 a" i; A
主链到侧链6 R- o8 e- g* q; K! k" D& X
主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链. s- q4 {* t2 A' Q1 ]
侧链到主链
% S) v" o; K) Y2 g  u侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。
8 g* b) N0 |" ]2、代码解析4 p* Q8 j' v% c: x0 j
跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。
! X; X& q" V3 C' ~(1)keeper启动
- O7 z- l3 z# ^  r整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。
- |( s0 }  ^! i* D0 jfunc (m *mainchainKeeper) Run() {* }& t/ u5 F2 U, s$ a
        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)2 I" O" G5 G) c% z6 b; C! z( E
        for ; true;
5 A6 j  a8 o2 }- zRun函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。
$ y1 s5 o7 w; V- {! P  L(2)主侧链同步区块
# \+ R2 F8 \8 s( ^Run函数会调用syncBlock函数同步区块。5 s1 \4 {. i- o* ~* G
func (m *mainchainKeeper) syncBlock() (bool, error) {! v& F. ~/ x+ `3 E: s5 }
        chain := &orm.Chain{Name: m.chainName}* y% y  P( ?: D0 b
        if err := m.db.Where(chain).First(chain).Error; err != nil {0 ^  D7 t8 _0 p
                return false, errors.Wrap(err, "query chain")
: y1 o/ x( q3 v6 S2 j2 t; q        }
5 f! a- k) d% k7 p0 a        height, err := m.node.GetBlockCount()
9 \' i$ W3 |! G0 G, K9 J        //..) F3 F, p' F( e9 Q8 f  d
        if height $ a% J0 }( V- V7 i
这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。/ p6 t8 U7 o2 W$ S3 |3 K
height
! t# u1 M% @! m) J8 O. u; K主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。
. A& @/ J; ~1 ]6 z% v/ C6 l7 \nextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)
7 U8 |- i1 P& L5 b0 t+ s! G& }5 H7 k9 F$ F  Q# L4 j. W6 X( z# {: {
这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。
; T2 [! d$ M7 b' h1 L. Wif nextBlock.PreviousBlockHash.String() != chain.BlockHash {
6 }0 s% n3 S- {5 B' E  E% E    //..
+ t; R% _" S- V: v}
* s0 T2 O* X4 V' {5 `; Y在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。+ e; U; {$ `$ e. @" o+ x
(3)区块处理
1 t" c( H0 |" i4 ^+ X& n+ tprocessBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。- h9 R6 P% d: U, l5 F  H2 s: W  a
func (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {
! e3 p1 P2 X9 e0 Z        if err := m.processIssuing(block.Transactions); err != nil {
$ |/ F' S4 h  ^. h7 [                return err
! V4 _! J$ f( ~& x        }
0 X( x  j: x* R- J        for i, tx := range block.Transactions {4 x* F6 ?  F) I" ^7 z( ?' F
                if m.isDepositTx(tx) {
9 Q6 M7 P+ j$ `" `5 }                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {
* N/ t( Y4 O: a                                return err9 o5 ^. Y+ W. B- ]6 L1 D1 }
                        }
) \0 O0 h5 `6 x8 y$ T5 M- _                }$ F* q, L# r' ^. H3 T" \5 @9 D
                if m.isWithdrawalTx(tx) {
. v7 k$ H  ]( v% y                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {2 i* }5 d! k; `" p8 E6 d" T# g
                                return err6 e) \* E7 `$ q5 Z: R+ e1 x
                        }
) q7 Z8 r7 f% I8 f6 `/ z% N                }6 ~! T2 [$ ~) ^: f$ \% A9 j
        }
- C8 K; ^0 D! ~* S6 B9 {        return m.processChainInfo(chain, block)
( B/ m  P) C2 K" q% S+ |- F5 e}
, K$ Y0 M  n9 S0 Y: m在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。
* M1 q9 Y0 q+ i( {m.assetStore.Add(&orm.Asset{# x. N7 I; M) l7 L& x
AssetID:           assetID.String(),
! A, j  p) K+ _$ n7 s! sIssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),4 o# [7 r1 b7 \. A+ e; U8 i
VMVersion:         inp.VMVersion,1 V/ m+ B% b; z; f
RawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),3 S6 j& [! K! a1 R; J( f. \
})
7 f) r6 r- c; E在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。# c4 g* N0 W% G0 K- l. ~3 _
func (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {$ P. h; e3 k: g& Z: F
        for _, output := range tx.Outputs {
& b, @: R, p) n8 R0 b                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {
- W( Q& X( R" U; p  i: i                        return true
2 I. Z3 o4 ]1 S3 H) Z                }9 s" b; G9 I8 k& `0 w* o- h
        }4 \$ @+ i& F: V& u& I% ?% O9 B
        return false7 i, p: C1 [& D$ n, l
}' U! `$ Y/ r+ X* n
func (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {  z; @- I. a$ q! j/ z
        for _, input := range tx.Inputs {0 s& k3 Y% I! g# \. i5 _9 x3 d
                if bytes.Equal(input.ControlProgram(), m.fedProg) {0 ~/ X" l" E( i% k' ~6 i
                        return true
7 }0 Q1 ?0 U8 `: |0 q2 L, d                }
/ E4 U/ B/ e" \2 c4 a! I; |        }
8 a( h, ?( M! e6 b3 Q        return false! X# N# o- q& f0 _3 Y3 V+ I
}
& [# N0 j, j2 }, W/ o看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。! E1 R& n- C8 k
type mainchainKeeper struct {
5 X8 p' S6 P$ h7 p. |& x        cfg        *config.Chain
5 A9 f( V- G5 x4 m) d* ]        db         *gorm.DB# p5 b/ d: f- b2 _4 x
        node       *service.Node1 B- ?0 ~' C; X" ?8 Z* ~
        chainName  string' w3 o4 j- f# `/ S
        assetStore *database.AssetStore
7 P8 g( V) m" }2 w        fedProg    []byte7 o0 i' y+ D5 Y5 {
}
: d5 {' {2 @0 m% o(4)跨链交易(主链到侧链的deposit)处理
- J9 h  `- y) Y! o, `这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。3 N% }. C4 e; Y/ k) ^& w
func (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {: L) Z1 e! Q) o9 a
        //..
' T& |4 k8 ]+ u! {6 d8 s        rawTx, err := tx.MarshalText()8 v/ x! `4 X# j# E  y0 X; o. m
        if err != nil {
7 c) n8 C9 ~/ j6 ~/ \                return err
. L4 E) Y) m0 ~6 ^$ X7 n        }
8 o" J' M2 s* {0 ^        ormTx := &orm.CrossTransaction{
" d1 I- k/ i- b! d1 @! A$ x              //..
% k: K: d* P* a# d/ R+ _" P        }
: S$ G: E. V" w3 I5 W) M        if err := m.db.Create(ormTx).Error; err != nil {% w5 d. c7 _9 D. G
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))9 C8 @, a+ d( B" f
        }% q- {- x( m( P" \
        statusFail := txStatus.VerifyStatus[txIndex].StatusFail
  m+ c* L6 [- W1 j( c- X% [/ |        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)
- V6 l9 ~4 J8 X* g( T        if err != nil {
+ q4 E6 C+ z1 j7 h# {                return err
* \6 I* X* [! u& k        }! Y0 e  @! o" u; P8 r+ |% j
        for _, input := range crossChainInputs {
5 F+ o1 n1 V. H- Z                if err := m.db.Create(input).Error; err != nil {: M5 x! a" s+ [/ k8 a
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
: c) N  v' M- C9 k                }
+ f' h' I- Q1 F: [: u( D) K" n# V        }
0 \0 ?  f6 A" u        return nil
5 m0 o" J, s5 z: i4 P}. z! k  x% Q: w4 O* Y" E
这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。; h) Z9 N$ f$ H9 i5 f! L8 i
ormTx := &orm.CrossTransaction{
" o" u8 A2 K6 d& N# u( |, D' g, l                ChainID:              chain.ID,
/ h7 x; b8 e1 u                SourceBlockHeight:    block.Height,$ X- H" }  @; h5 O; t
                SourceBlockTimestamp: block.Timestamp,
% j1 P3 _. C, v! W7 W9 _                SourceBlockHash:      blockHash.String(),5 S' M# Y" f; F1 X  w* q2 u/ D
                SourceTxIndex:        txIndex,; D( B; u+ ~5 @, l% a7 g
                SourceMuxID:          muxID.String(),2 s9 T# o8 G4 `$ q+ p/ b( N
                SourceTxHash:         tx.ID.String(),
3 Z! M: Q' X3 z+ o5 G5 s. I                SourceRawTransaction: string(rawTx),0 S) n: W4 a8 {3 C: D8 L% w
                DestBlockHeight:      sql.NullInt64{Valid: false},4 W; |8 S7 C. `$ g: v6 G9 E' J
                DestBlockTimestamp:   sql.NullInt64{Valid: false},
. Z) F; S2 i' r( ]' x                DestBlockHash:        sql.NullString{Valid: false},
* E/ }$ _( M1 w/ C! G2 i                DestTxIndex:          sql.NullInt64{Valid: false},
* M8 Y9 j! a; ]4 t7 C+ n                DestTxHash:           sql.NullString{Valid: false},
" D: X0 P; S: s1 f, @                Status:               common.CrossTxPendingStatus,
, L, x2 {) J4 B- o7 |: p        }/ m3 ~4 d# S, U4 o: E8 G
创建这笔跨链交易后,它会将交易存入数据库中。
- K% v) E0 a$ K+ J% [. C, qif err := m.db.Create(ormTx).Error; err != nil {! W& S- l/ ]" S& G7 y7 J
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))4 P( t1 Q( n3 S
}# a8 P8 t  n6 w9 ~" R, O
在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。
# O5 V4 S4 k0 P! o/ |3 R/ ~func (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {1 n3 L+ P$ \1 S! M! t% _
        //..
3 K+ O( `5 b% E        switch {- z$ y9 p6 B& w5 ~/ g7 W
        case segwit.IsP2WPKHScript(prog):. R" y/ ]* }, l
                //..
# Y) K/ X3 k# Y5 {* ^- G) {# d" k        case segwit.IsP2WSHScript(prog):
8 p4 D& M: @% ]9 n) V/ w                //..
. P# g3 b' x' r+ y; N, @        }: y6 H# ], ~5 i# r
        reqs := []*orm.CrossTransactionReq{}  S6 b: `7 [; x. J/ Q
        for i, rawOutput := range tx.Outputs {# x% M( Z7 }: T3 V' ~
                //.., n8 R5 Q" T6 K& \
                req := &orm.CrossTransactionReq{9 \& k: I- l6 N% g
                        //..
/ l- Y  K" `2 I, m- _6 J! F                }
: v. l4 R( c3 M1 Z+ t                reqs = append(reqs, req)
! P* a  @0 g8 K  Z$ l! M/ W        }2 h3 d' Z& }2 N& [8 u. h
        return reqs, nil
: R. U  Y2 [4 b( l( Y5 M( t}
/ _' }9 h- s& G& Z) p很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。5 Q6 w  `; U9 J1 P! e7 }
switch {; @! D: Y9 F: v
        case segwit.IsP2WPKHScript(prog):. f$ G$ R. T: }% \: K+ {( p
                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {/ w8 E9 O) }' A- u1 k3 V6 y/ {
                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)2 V& i8 }) _8 A5 P! k
                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams)5 i/ ~2 b& I* n* e1 R( I% m% T0 Q
                }, @; \. f* C+ b0 d
        case segwit.IsP2WSHScript(prog):
4 L+ q; O/ d1 Z; ]& B6 Y                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {- ]  J  {3 j% G
                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)
+ P. q4 c  b- s                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)6 V, O9 f0 K" C' c$ I/ O
                }( a7 Z, L) \3 i0 ~  S" t
        }
+ Y: E; ?. R# F在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。+ N  D/ H' p1 u1 X
req := &orm.CrossTransactionReq{
% v+ {5 X3 E' K& r  E) L5 O" ?; T7 [2 {   CrossTransactionID: crossTransactionID,
/ k% G7 K- p% O: ~) H   SourcePos:          uint64(i),
" b( Q+ g, E7 ~# q+ [. ?   AssetID:            asset.ID,; r' p  @. ?, ?* ^, u5 d
   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount,
& t! P: N2 ]- o' U( W   Script:             script," f7 g0 _! b; A8 v! k4 I
   FromAddress:        fromAddress,# w7 L6 w0 D8 e9 K! |; K" V
   ToAddress:          toAddress,3 C7 O% w8 W5 a( @
   }: K9 x1 ]) `5 U; k9 r
创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。
+ C  M3 s4 N( q8 Ffor _, input := range crossChainInputs {
- y6 O2 J5 [; b- n# l0 ?                if err := m.db.Create(input).Error; err != nil {
/ o: M, {8 R1 ]. B$ @$ D                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
0 d4 F: A/ L8 L% M5 @5 k                }
5 P5 i, [" P  g9 A" H* e1 y; W2 ~}
' a4 `, C1 ^# q8 A4 |到这里,对主链到侧链的deposit已经处理完毕。
+ o% x$ n6 J. y- T; K+ c(5)跨链交易(侧链到主链的withdraw)交易处理
$ W$ z) }* W+ [4 U% @: z$ b  U这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。
4 _0 T" Q- I) b  [: g! o3、跨链优缺点) _* Z& `# |# C& v% E% Y& o
优点
. n) e! Q# |8 k; h(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。
8 r/ Y- |& {* q; Q/ ^(2) 可以根据不同需求实现侧链,满足多种场景
$ k/ \0 e# \/ S( T缺点% S3 E' X6 G0 S* Q
(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右8 P# ?& _# `8 q( \, ?: @2 V% N
(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大
5 w5 ^8 E7 e4 F9 d9 O(3) 只支持资产跨链,不支持跨链智能合约调用8 X, ^8 y6 i/ [1 Z, B6 m0 m
4、跨链模型平行对比Cosmos0 V  {( i7 r, d7 f
可扩展性: e7 I2 e" V. N* o* Q0 N( \
bystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。
) O7 ?6 h; d$ L6 h6 ]代码开发进度
, I# V% p1 e5 V" m+ tvapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。0 s. J% d2 c2 z: x/ v- s0 A
跨链模型
) e0 Q3 {: _/ @% c/ C+ u) Q! Xvapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。
! V1 D, S* r3 @. R9 N) `5 t2 C5、参考建议: P3 B9 ]" ~3 [5 P
侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1