Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
189 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。& m5 w* Y. \* [' F3 K/ C  I
0 p' K6 ^9 w- a' v& ?
Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。; \0 E$ m% \, z
主侧链协同工作模型
/ b) ^' E; c$ x- x/ g( m2 U$ k5 `0 t! H- r
1、技术细节/ ^, W7 R( r, ^% C2 C3 W
POW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。6 M$ ]! Q$ C& g6 m
而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求( L  t$ _7 v& T. @- o4 l0 e0 d
(1)跨链模型架构% {. }% `: t/ S9 q9 U5 ]* b
在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。
, I( ^+ R. }4 B4 w(2)节点类型# h6 D, Y' |) w1 N3 i# m
跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。
8 B9 Y/ l2 x# J4 z4 F  e0 {0 V0 Q# ~(3)跨链交易流程
& h3 \' p; e$ [主链到侧链
3 V8 d7 u) B! J: c* _5 G2 F& b主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链2 X: w# W. _" W
侧链到主链; F( I/ d1 x" G3 k( w
侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。% b5 j4 L! k% `/ g) ]* z- Z( U# U
2、代码解析* T( R+ r" D7 k  r
跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。
) i6 T+ o! {& c(1)keeper启动
$ J+ C2 d0 F. y4 Y整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。- L, C0 f; t% O
func (m *mainchainKeeper) Run() {3 G+ |) w$ Y! C' r, u  u
        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)
0 T1 [' }! v' W2 F        for ; true; 6 v$ I5 a6 X; m  j) f( b* s
Run函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。
4 {" s' K3 R6 ]! ?" E(2)主侧链同步区块3 g! d* S& f: w& x2 q! }2 K
Run函数会调用syncBlock函数同步区块。
. f" U# ?( S, L( Q+ [  F- L2 p/ j" z+ qfunc (m *mainchainKeeper) syncBlock() (bool, error) {6 n0 Z& E: H: @  v: s; Z* T
        chain := &orm.Chain{Name: m.chainName}, q$ ]3 z, T! p$ I8 }! E% F
        if err := m.db.Where(chain).First(chain).Error; err != nil {
5 j/ b+ w, y! }1 b& z                return false, errors.Wrap(err, "query chain")% I) h. J& r/ Y$ b- T
        }
$ h9 }# U- I4 I% S        height, err := m.node.GetBlockCount()
' @  E& m3 @6 `+ F" W        //..
# d- i. A' s+ o0 G$ c& V6 t. b        if height ! I& P9 K, D! l6 q
这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。
" n: T! K! d6 w9 Q/ @) Gheight
' e( Z4 z, \6 A+ w# V* T$ Z) k主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。0 i# I3 k" m5 H  i5 a( N
nextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)
) g3 O* @2 l: H* o8 I9 G/ X/ t" p
这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。" ]: B5 H6 d" w. ~
if nextBlock.PreviousBlockHash.String() != chain.BlockHash {
; o0 Y+ a9 N' \- _0 S! e    //..
; i6 y1 a9 S0 G+ F}# w$ ?4 K# R/ A- R+ a
在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。9 M8 B1 i5 |% P+ v
(3)区块处理9 R' n4 b; `- Y
processBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。5 G8 Z$ {% v7 o8 ~
func (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {% P0 a2 ]5 r' Z) k9 b& D) {. U
        if err := m.processIssuing(block.Transactions); err != nil {4 y! ^8 W+ D2 s
                return err
. O' s5 L  Z6 o% K/ X        }
$ ]  B4 e* o' }) i5 [0 p        for i, tx := range block.Transactions {& C- Z: ]* l0 a+ b) c; i* w
                if m.isDepositTx(tx) {1 E" @" i7 S7 _* w
                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {
2 i8 Q4 L: U) M, P7 O* N. ?' g  h                                return err0 i9 z- Y6 J& v: Y9 ?
                        }: `) B6 H! M- L7 n& D& v1 Q
                }
1 k4 p; O: d+ r                if m.isWithdrawalTx(tx) {
; L* ^4 ]" X0 D  F                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {
; l5 h9 G5 A  H" n0 e                                return err
' r$ y0 X& t4 k' T- H4 a, D                        }1 _4 O9 a! |+ w3 P; p
                }; E  `4 x' [  X- F2 S
        }
+ S  Y; V: {2 p3 m1 N        return m.processChainInfo(chain, block), l6 I7 T9 t( J4 ?$ C) w
}# Q% V3 @1 u7 H
在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。
& Y, q5 V- A& z5 X7 o' \m.assetStore.Add(&orm.Asset{9 S1 e, _+ o* v: x- K8 v
AssetID:           assetID.String(),+ w5 C; x% e3 z0 W. p7 r( ^6 u
IssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),
: U0 Y5 M6 X* v% ^/ E4 eVMVersion:         inp.VMVersion,
" k! x* g, @/ G3 r- D1 zRawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),/ }8 \# b/ y/ J7 n
})3 L1 _6 J; Y2 o' P, J6 Z$ g5 n
在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。+ v% w5 s4 C2 G& ]
func (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {
: J$ Q% }/ f" ]8 d" |: x, E        for _, output := range tx.Outputs {8 [$ [3 y7 u" z. [/ ?
                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {8 m' s4 w& [1 l) f" m8 ^, T4 O
                        return true
0 \& ?# P7 J" s) J                }1 C5 k/ [0 ?5 C/ E; ^' z# g
        }0 A6 {( o& ^$ M+ ^' R1 F7 Z* F
        return false
, N: F& ?) x  e: G5 r$ T}# a1 y4 h, E  F+ s3 O; [# D
func (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {
! o" L  b& B2 Z; h+ {: c        for _, input := range tx.Inputs {1 w' T  H! N+ I* q; Z" z' j0 A  J, u
                if bytes.Equal(input.ControlProgram(), m.fedProg) {
# Y9 D( u" c5 _7 x6 ]                        return true$ t1 K" p2 w# @+ C6 E$ @* H
                }
- m3 A$ |2 M' N. f2 T  M" F- u        }
. S- }  C( }# j* }: R7 s        return false
2 Y8 A% ~$ ^2 {# [5 ^% A! R}- G2 Z- V! l; f# V9 |
看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。: x' B! L+ Z1 W8 x" h& f
type mainchainKeeper struct {
( f$ r4 P7 x& v" ^  W2 m        cfg        *config.Chain
4 _. _% n5 N2 F( ]. I        db         *gorm.DB
: z$ n) B) O. r2 M$ |        node       *service.Node! d  B. t2 m) |5 u1 R; H# `
        chainName  string1 I% x7 n+ Y; {, |; `% B1 y5 b2 f' m
        assetStore *database.AssetStore
+ s# _9 R+ T1 k9 n1 L; s        fedProg    []byte6 Z7 D0 Z$ M, r" b0 E! ]. ]
}5 b6 x7 j; K* l2 N0 w
(4)跨链交易(主链到侧链的deposit)处理  c& M5 Y5 p4 E( S
这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。
& ^% r" v) t; S' Afunc (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {% |9 W1 y8 v5 Q2 x- H$ j
        //.." `) W/ m/ r. M0 L
        rawTx, err := tx.MarshalText()
3 _* C1 f* n0 N$ ?3 L9 p2 k        if err != nil {
, f7 S9 G  E# D4 _& ]' G                return err
& P, W  q5 o5 J( S        }
* t- K) a! A% z' b$ @! Y        ormTx := &orm.CrossTransaction{0 T* C1 j$ t9 ]0 u8 D& a
              //..
  N  U! {6 R6 F6 y. Y2 L! N        }: W3 r/ Q7 ]% j
        if err := m.db.Create(ormTx).Error; err != nil {
& Q2 E- d, q' B* ]- I" f                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))2 f8 F. H; z3 ^& q+ Z$ z
        }5 u( N5 S" r* C5 m
        statusFail := txStatus.VerifyStatus[txIndex].StatusFail
: H+ Z: Y- N! C        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)
5 ]1 Z9 j" {- _+ \        if err != nil {  I2 i5 g4 O, B& ~+ n
                return err3 E. x5 Z5 X! @. I
        }8 o  r) O; E% D2 L$ @
        for _, input := range crossChainInputs {
! \% `# i& v4 f% ^2 n  Q% L( Y                if err := m.db.Create(input).Error; err != nil {
( j! e/ b/ B# u. |" u1 k) a* E                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
5 V* r" q4 `/ d" D  p  J                }8 p! h+ u( x" p3 }" D; @
        }
  t$ G8 D, j$ n: H* m5 B        return nil" K2 r# R% N( n& @% [+ c( N) x8 T
}0 p* t! C, a3 C1 ~2 U: T
这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。: t# u8 ^. k' D3 D7 Q% K0 D
ormTx := &orm.CrossTransaction{# h  w2 |" N6 e  H, D- q2 C
                ChainID:              chain.ID,
# J& p) _. D/ d$ N5 v5 Q                SourceBlockHeight:    block.Height,
( g& `+ ]1 a& c0 h) W$ E                SourceBlockTimestamp: block.Timestamp,2 x" \& d. H$ [) C! W
                SourceBlockHash:      blockHash.String(),
+ T; z" F$ |& }' X! c- Z- H                SourceTxIndex:        txIndex,) V9 ~8 Q& L4 T: R! x9 e  v" l
                SourceMuxID:          muxID.String(),
8 h4 N" o# B3 E# a6 w& c' V$ N                SourceTxHash:         tx.ID.String(),
) l9 t' F$ y4 A0 s4 ~! ]: {+ X                SourceRawTransaction: string(rawTx),* a2 U- Y1 q! T1 V* t8 ]7 S- T
                DestBlockHeight:      sql.NullInt64{Valid: false},
* C1 ?8 o  g9 T" s/ @+ r/ ~! O                DestBlockTimestamp:   sql.NullInt64{Valid: false},
% T" @3 q& i* }" _- f) a% \7 A                DestBlockHash:        sql.NullString{Valid: false},
/ h5 g) {7 g1 H+ H0 [                DestTxIndex:          sql.NullInt64{Valid: false},
2 G! O8 N# d! }6 n# ^1 ?                DestTxHash:           sql.NullString{Valid: false},' k' a5 w9 P4 F6 h: G1 n( [9 m5 H
                Status:               common.CrossTxPendingStatus,& T% f9 \( @' i! d4 H
        }
* T- k1 A$ e) C创建这笔跨链交易后,它会将交易存入数据库中。$ a/ b, O1 I# G& _# y; ?, Y0 j: V
if err := m.db.Create(ormTx).Error; err != nil {
+ f/ ^' @' w. `% }3 L# t* u                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))# ]- ^/ {& g) t5 a1 K' H
}6 b, o  X! n; c. ]5 F7 B: R
在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。
4 I% G& t  Q' sfunc (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {" U  M8 B4 Z2 y6 \0 }$ a: L0 p
        //..
  n# Z: o1 o9 H0 j7 v8 {( F) C        switch {& y+ c2 S1 \/ ~3 g# j$ _
        case segwit.IsP2WPKHScript(prog):
7 J+ t  X' B4 ^3 E* J                //.." d& M. g9 {  O$ O7 B6 Z
        case segwit.IsP2WSHScript(prog):) N9 N0 _1 d- z6 L
                //..  c+ f1 i7 s1 [! a( v) I1 O# ^
        }
0 I* R0 V( k, L0 R* Q6 G; ~9 t        reqs := []*orm.CrossTransactionReq{}
5 E8 Z4 F6 |. g        for i, rawOutput := range tx.Outputs {5 z( `" m) W( l- H9 u) J& e, f# f
                //..
) o& h$ d& O8 H8 W8 A# t/ }& }3 A                req := &orm.CrossTransactionReq{
- c5 d: W. w" ?* d0 ]7 [% x                        //..
8 L5 _- R8 H  P/ O0 P; |                }
$ B& Y  L' T+ y+ D/ ^                reqs = append(reqs, req)8 o% w0 j) Y( s* Q
        }% O0 V  A% G2 K5 L
        return reqs, nil  R+ m0 J9 ]  G5 _: u& d
}
* ~8 B( }& b  c1 e3 f4 Q: p很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。9 W, f# ^( ^* j7 @& r& |# f
switch {
3 s, c' H. g0 D, P0 T* i        case segwit.IsP2WPKHScript(prog):8 A% Y; B6 f: z8 S7 p' {
                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
+ N% ~& \9 t( w, q$ S8 h) p: _                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)
# I# `% X8 j& Z9 x" C5 s                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams)
; k* ]6 m4 v1 ]% i  ?1 \  j/ }                }( u; {! l$ b! h
        case segwit.IsP2WSHScript(prog):$ Y) n$ a/ t4 O* `+ A/ X
                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {5 I& L; e$ B& F$ n% r
                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)
; f6 w& r% n- ~! E                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)
* f6 p5 p, ?- z1 A                }
$ `  L4 c4 n" F* M* K6 L" U        }% I  Q. n7 U; `4 X/ M
在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。, @1 i7 o+ b: N$ U
req := &orm.CrossTransactionReq{( X( ]. ?/ F+ Z
   CrossTransactionID: crossTransactionID,8 O: Q0 B0 e: y, ]% o* N, I
   SourcePos:          uint64(i),
4 t$ E2 `+ V% u& q. _3 m. r   AssetID:            asset.ID,
; g0 q# e$ y2 N+ N7 |' K   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount,
6 D% \# N4 ~8 [( G1 ~, q   Script:             script,
! e( I' q8 k9 N, C! k   FromAddress:        fromAddress,
! ]- A" p9 F7 L1 G5 g, X" D   ToAddress:          toAddress,
$ S5 s; P2 |( v* q# v/ j- W   }
5 p) w8 t* I8 T: o" ~( A# }0 f创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。
" F' k/ h- [  Y6 s, xfor _, input := range crossChainInputs {" E$ U; F+ M% s8 D/ S
                if err := m.db.Create(input).Error; err != nil {
; u9 x0 v8 n$ M& D% m$ D                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
  _4 H- T) l( V4 j9 T; X                }& D" [: }6 j7 r; ~) i0 Q
}! m. L9 p) ]. [  M3 T5 d0 Q: K
到这里,对主链到侧链的deposit已经处理完毕。
4 g4 E, ~: a( u# A(5)跨链交易(侧链到主链的withdraw)交易处理
0 P1 Q) ~- X4 v5 i6 `这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。/ ~9 y  c/ _$ X" I, T% l0 o% x
3、跨链优缺点( r9 t( @: ~8 a& V* _! {6 z
优点6 v- P  e8 J9 Y" G2 @' l1 _0 }
(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。
4 X2 h9 V- h& L. @" D9 g* b(2) 可以根据不同需求实现侧链,满足多种场景5 [4 w! r8 I0 f3 d( ^2 `7 e
缺点
$ @7 O/ V/ e5 z" u9 ?(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右' {  A  @" o  J5 _  a- ~, I
(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大9 G( q- z2 R5 y
(3) 只支持资产跨链,不支持跨链智能合约调用
, `- u. Z* c: P- v! v4、跨链模型平行对比Cosmos
3 F  v. W# a% s* C1 ?, e可扩展性
! B6 D" w* s% S9 abystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。8 y" w& \% h+ S7 ?1 Y6 _: I
代码开发进度
  J/ Y/ F" g& c. c" Wvapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。5 J; R7 {1 L" J/ D7 A  i6 J2 C
跨链模型, D+ |- I/ }3 M2 d( A: T* @
vapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。
: t$ M) `, k% u% J5、参考建议: f$ V$ e2 ~5 l9 D" _8 u
侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1