Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
216 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。/ E" P" ^3 c& @: j
7 |  s; G, J6 a$ ^& X  F$ ^8 _. a: V
Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。; p# h. n# s5 a8 |
主侧链协同工作模型
/ a5 y  l0 h( y5 V9 M( ?6 z- e8 P$ m7 U7 E6 m) V
1、技术细节/ l# d. ~% Z9 |' e
POW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。8 {' G0 C& J) ~1 z5 X+ t+ k
而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求
( ?1 o/ g" H0 |% h* r, h1 U(1)跨链模型架构
& h1 I0 Y" ]+ b; ]- S在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。0 s7 K  B3 F+ f6 x: q) Z
(2)节点类型1 X+ \: {5 F% t( D. Q8 E
跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。
( W: Z! d! B+ o' B( J! y(3)跨链交易流程
/ J, ]. }& K( V3 k- o主链到侧链
  }9 J- Z" b' M/ V0 V, ~主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链
  R+ d  n' B3 s. ]! Y# L侧链到主链
- H" ~; p& l% k. R0 q/ [3 N. n侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。* {9 t  ]" s! R: q' @) D) Y( ]
2、代码解析, T. X: @, G1 ^$ w
跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。$ v( k1 J  g4 t$ s: D- O
(1)keeper启动
4 l0 d/ }% F# s/ H# |/ w2 F整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。
4 N9 z. a$ J: ^; ]( W( ofunc (m *mainchainKeeper) Run() {
7 q( X8 b' ]  j- K0 q        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)
; j- A. k1 U( Z) W% p        for ; true; / P  c+ h" v1 U8 @
Run函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。
# x- r) D/ _  u( W* ^6 \(2)主侧链同步区块, V# a6 L: K. h" ?
Run函数会调用syncBlock函数同步区块。
1 z' i0 U% Q: kfunc (m *mainchainKeeper) syncBlock() (bool, error) {
) W5 H4 h4 T( G, g+ P  n( D% }8 V2 F        chain := &orm.Chain{Name: m.chainName}8 D) `/ O: O% Y% F3 H7 A
        if err := m.db.Where(chain).First(chain).Error; err != nil {& d, i; P' R- ^8 ?8 d) a4 U
                return false, errors.Wrap(err, "query chain")
1 w6 l$ L( n% j) k" j# U6 c, g        }" C8 k( {2 [4 A& B, F
        height, err := m.node.GetBlockCount()" S% b* K$ [$ O
        //..
4 `+ u4 U8 ~0 u3 {( X        if height ! h# w6 S$ x6 _8 `  I' k- X
这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。' P# H7 y0 ^* F
height
; O5 o9 F5 t9 w4 C0 R( I0 v: Q主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。$ @  C$ O( h+ q6 V# H# o
nextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)
( M. V5 l/ p- k* j/ u, @! m
) h  L9 [4 d- A# j这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。6 ^$ K, z1 V* p, N% o0 |- {
if nextBlock.PreviousBlockHash.String() != chain.BlockHash {
( T  M8 Q7 G  ^- z# [    //..
9 R- q3 {; N! Q/ ^- F}
" e! n  W2 L+ u2 K5 D* V: J- i在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。
) a, K" {7 i5 i' W/ @* n; O8 _(3)区块处理
/ K" m. k4 ?3 X$ }3 ^# G1 EprocessBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。
# ~4 E7 a' x/ [1 Y: q2 t+ @; Zfunc (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {, F) w$ G8 ~, j* A0 r7 d+ U
        if err := m.processIssuing(block.Transactions); err != nil {
$ A  U: i7 Y4 h8 m6 x0 N0 K                return err
9 r3 m, ~7 M0 T& d  A1 ]        }
  N# |8 d% o2 I  O9 r3 h# P, @        for i, tx := range block.Transactions {& d: r+ `- q8 r0 |
                if m.isDepositTx(tx) {8 U& ~' s, @2 o! T2 t1 D. p
                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {/ @: D% r/ B$ M
                                return err2 Y$ W2 w" K$ n0 I% ~2 _, S
                        }8 g6 `7 [6 m( |  e7 c
                }7 {7 ~) j5 G$ ~* u- m% }0 {" w
                if m.isWithdrawalTx(tx) {$ i+ d5 Q/ u- W. Y8 q
                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {
1 b: g. K. T$ w                                return err
/ s4 i* A) r6 @# i5 i# I; H  {                        }$ r* k  x/ K! P% M
                }; x* u6 |; b, L% t: S
        }
% K, _, e! b+ j2 K; n. j        return m.processChainInfo(chain, block)3 |  T+ b( z* a
}
( D% J# {& M6 A8 @/ U在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。
4 t& y8 M0 K6 t2 q+ e- {m.assetStore.Add(&orm.Asset{5 q( h: e4 q) X
AssetID:           assetID.String()," X! u. [& y3 C* P. Q4 V
IssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),
2 _! b8 P4 _' ^- I' ^/ r) fVMVersion:         inp.VMVersion,
7 m( e# _9 r3 y& V4 r: fRawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),
' ]3 ?6 `1 `; i$ T1 N6 a3 j})
5 g0 y- z3 A8 @: V在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。
" ^* @1 s' V0 c: K% bfunc (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {
  m1 o- l, T. v5 S6 N8 a) O        for _, output := range tx.Outputs {7 j9 x3 q- y  P% o$ B
                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {
- J6 `- N) d# Z                        return true
; f$ `0 f6 f$ L' w2 O0 W- G; L                }. _) l2 v0 N& y, K! H/ I8 G3 d5 v
        }# H: S. h1 g& t0 x. S1 w, `- ^
        return false
. }/ r2 p9 b9 e5 }}' U' D9 {6 W0 g7 [9 q' V" O9 ~
func (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {
2 w0 ^$ q% G1 U% k1 I+ F- d        for _, input := range tx.Inputs {( X% X5 P  ?  t* K* W" P- G
                if bytes.Equal(input.ControlProgram(), m.fedProg) {+ H  @. O* {/ ~1 ?. L% T$ [3 R1 ^
                        return true! r3 {  j/ \/ {% H
                }
& _( B$ z: E6 k3 [; ]        }  R9 F# c/ o& t+ g1 n  k9 {/ A/ l
        return false
* X5 a: o" [! ^7 H- \# \$ A0 y}
. s: A+ B# I8 k# Y$ j看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。
( ^0 B8 x: f$ _: _9 ptype mainchainKeeper struct {
6 Z$ `: M, V7 [0 |: n& ^2 f        cfg        *config.Chain0 B% U: T$ X0 u5 I
        db         *gorm.DB; D6 M) `- v$ |( K
        node       *service.Node
0 t* G  k4 A$ M8 h2 _7 q        chainName  string
+ e% V0 z) r! |# L! `0 F! D        assetStore *database.AssetStore/ Z" ~, i# z( U9 H$ L
        fedProg    []byte
6 Z4 p' @6 ^7 P6 `}: B) }  i  H% @. V( T# q" c
(4)跨链交易(主链到侧链的deposit)处理
+ y; @# i1 Z0 }# ^9 T: `这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。4 o. q4 @/ d8 y# D8 S2 Z
func (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {1 r0 x' q# H' a
        //..
! c0 m8 W6 {2 P0 U& x        rawTx, err := tx.MarshalText()# m; G% u7 ?" i$ j) F
        if err != nil {9 e1 I  V! U, }; U8 Y
                return err
. h2 q/ `0 E: W$ l" b1 b4 o; R        }+ \/ h6 r' C' _2 z- l2 N- F; F
        ormTx := &orm.CrossTransaction{
- s5 |' t& |) O4 D' x# ?; F              //..
/ W: e$ k" `- R! Q# q+ h. I. G        }4 i+ m% w1 x' F  O4 o/ w; A
        if err := m.db.Create(ormTx).Error; err != nil {
' d2 h2 z+ O3 ?( O                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))0 S. U1 p9 k1 @
        }
2 [& m3 ]: ^' z: M" t1 c        statusFail := txStatus.VerifyStatus[txIndex].StatusFail( e" l! k& [+ |
        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail): T3 _* t) V5 Z$ i# |, B
        if err != nil {  O; ^# ^' r" w  k3 e% _% }
                return err/ X0 o0 C/ {5 f; l4 G) N
        }( T; Y  m. D; M! o
        for _, input := range crossChainInputs {& |: O2 m- o, h. `
                if err := m.db.Create(input).Error; err != nil {  X! a  K2 k" q" Q; h
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))5 R' o" \7 r# b5 M+ }
                }
+ P+ ]( `7 W2 l' X. M8 l        }
/ B3 C8 w% M) w        return nil
3 i) R! G$ Z7 E! A9 K2 r}4 z9 V9 p# e) @# V
这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。- o( a/ F3 i9 E/ q3 m% y! Z" N
ormTx := &orm.CrossTransaction{
- u1 ~* ~) v% S& w                ChainID:              chain.ID,8 \0 W% B6 ]4 O& G( m7 u4 s
                SourceBlockHeight:    block.Height,9 R& ?  s- d7 o
                SourceBlockTimestamp: block.Timestamp,( V) Q' [! X. [& D
                SourceBlockHash:      blockHash.String(),
3 B) u4 }& ]7 G) D                SourceTxIndex:        txIndex,
+ q5 q2 t) `8 ~) R' f4 Y5 b& H                SourceMuxID:          muxID.String(),
3 j3 P  q6 b: z! i                SourceTxHash:         tx.ID.String(),6 h& j8 ^6 V) Y3 z) I
                SourceRawTransaction: string(rawTx),
2 H# d+ v2 h0 ~' F                DestBlockHeight:      sql.NullInt64{Valid: false},6 S( I4 E8 L7 K) t
                DestBlockTimestamp:   sql.NullInt64{Valid: false},
+ {8 O- k% e  }5 a                DestBlockHash:        sql.NullString{Valid: false},4 g9 L6 z4 a% T5 }  ^: p% _! V
                DestTxIndex:          sql.NullInt64{Valid: false},
! n4 C3 k& Y  F' @' c) o  e                DestTxHash:           sql.NullString{Valid: false},
) X; h" n# Q! k+ I4 w: J                Status:               common.CrossTxPendingStatus,  S# K4 n0 j$ y
        }
5 f. B2 h" S/ D4 s创建这笔跨链交易后,它会将交易存入数据库中。5 I/ y5 @: B9 q! t# A
if err := m.db.Create(ormTx).Error; err != nil {
2 Q; ^! V: i; e0 Z$ `: t8 j                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))7 `0 k( e8 E0 D, m% L
}6 r' M5 F  x  S! S4 n  _, z
在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。- p( R; a5 }  R' J2 i% H
func (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {
; E* e' X# h0 M        //.., [; D' U; {5 L8 ?" S. u
        switch {( y' u2 I. B5 Y7 D+ ^% \2 V
        case segwit.IsP2WPKHScript(prog):, T( |. h+ X6 A9 }- w) m
                //..; ?2 ?% v$ h  S: f& h
        case segwit.IsP2WSHScript(prog):
  A8 ~" W. Y1 Y0 ?) C                //..
5 a1 D/ \& }0 i5 R* L        }
3 [! t$ e& [2 b1 n9 n        reqs := []*orm.CrossTransactionReq{}
& T5 Z; Q3 Q4 b; u% \        for i, rawOutput := range tx.Outputs {
% j0 H  l4 r( @- i9 t' k! R( \  l7 @                //../ P7 t! C! `! Y, X7 B; p4 \; t
                req := &orm.CrossTransactionReq{
. s, u  a6 y- \( J6 u2 E                        //..
0 F6 i+ l7 ]) [8 p3 R                }& J# R: p% j. o
                reqs = append(reqs, req)
. c$ t) b! b) A4 e2 W        }) u8 v! @' R1 z3 \- M
        return reqs, nil
# S& T. ~0 J7 \4 t}9 s1 B7 y5 y8 _; @
很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。  |: G, k6 J8 D* d2 s
switch {/ |) Z8 ~2 y# t! b
        case segwit.IsP2WPKHScript(prog):
& j' p+ J+ F2 n" j) G+ t0 \" ?: L0 k                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
9 ]- r/ y4 J2 x; I* S                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)
# l- w1 O  i: L& D; J                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams)
/ Q" y! }& _4 A1 e2 t* p% u: B                }
% X/ R9 @, `; f  y6 f        case segwit.IsP2WSHScript(prog):
3 c+ X7 o3 X% {" m, o                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
4 x& o' A1 J3 K8 A: w                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)
4 H- r* y" h% C/ s% v. I$ c5 U                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)
3 j( s$ g6 v0 T; F5 ?' k& ^. x                }
0 S; i7 ?9 Q' E' q, `. `        }
' z5 m2 L" b/ l% Y6 ?! C# ~4 m5 Y在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。5 q5 ^: f. N3 K/ w; H. M9 s( R
req := &orm.CrossTransactionReq{/ p' q$ _0 X% T5 W( Y& x) E
   CrossTransactionID: crossTransactionID,
7 C$ j9 w) w, |$ T9 V3 n# f! S   SourcePos:          uint64(i),( k. Y1 `! R! K! t  ^/ S
   AssetID:            asset.ID," Z+ `, d) }. j4 B4 b
   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount,- |* @0 g3 i% s  g1 a
   Script:             script,9 `% x6 ?* {4 |: F1 e
   FromAddress:        fromAddress,/ C% ]+ d+ g, a' X% ^. j: A
   ToAddress:          toAddress,+ J8 w+ m0 c1 Z
   }! [5 X8 u1 t; k. s; K- B6 ?, o
创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。
* c+ E% ?$ w& }$ T8 O" x- m+ q) ^for _, input := range crossChainInputs {( \; [/ F' J; z6 z9 q. m( A
                if err := m.db.Create(input).Error; err != nil {
$ c3 k, ^. i. n+ z9 u6 F                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
% a% I' d6 Y; D# |, W                }& k0 e: E/ s4 w4 p: c" Z' g* i
}  O& y) Y& p& ^, `
到这里,对主链到侧链的deposit已经处理完毕。
3 v! M9 n6 S! V1 O/ M, M4 A  W- B& c(5)跨链交易(侧链到主链的withdraw)交易处理+ r2 c/ v  w+ y2 m/ _' G
这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。
* b8 w1 i- {% @3、跨链优缺点7 x  b' _+ D% Q" A  c1 D
优点- ?1 Y% ^" r* {/ e: o1 a
(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。
) [, r! _7 \$ I6 Z3 f(2) 可以根据不同需求实现侧链,满足多种场景
# a6 Q! t# b7 E缺点0 B8 ^# W; B" d& x4 T. Y. y& U
(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右6 j" M5 p' z. g: K, n6 W1 w0 F
(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大' @) F0 W$ G, q* X7 R
(3) 只支持资产跨链,不支持跨链智能合约调用
3 z% @8 @1 }8 u+ [  I0 f) L3 C4、跨链模型平行对比Cosmos
5 ?( {, h& g9 ^可扩展性+ ~2 ]  d' d3 [2 R
bystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。
9 i. {+ N. J( ~/ q代码开发进度- {2 L* M. u0 f* a  `" r
vapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。
$ S+ x/ ^/ Q9 F8 Z" a5 T跨链模型
. x# h+ m* X5 b' r5 }7 O+ v3 U6 }vapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。, \+ i# P6 m( J! @5 q3 e
5、参考建议0 T& x7 n5 o# J5 Z8 l% g' A  @7 x, ^
侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1