Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
132 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。0 v2 }3 w% b0 j1 G( T* V- n

3 y  N) ?  V8 q' x0 i/ }; b/ JVapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。! i+ p/ F) p6 v7 n; [
主侧链协同工作模型
  G  p* b5 c# Y6 o' M
) j7 _; y( d5 K7 U1、技术细节3 H( u/ k* }# B$ F# W3 i+ b: P
POW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。
+ v% P; e, u; I) J% j, R+ p$ z而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求& A" ~& b, q2 k' u4 ?/ @' ?
(1)跨链模型架构
1 E# H8 h$ C- @在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。7 h. d+ E3 V; c2 r* f3 _
(2)节点类型* y4 m) s9 ], n) i. d- z' I% T% I
跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。. R$ x( x) d" y! s5 n+ ^! @* o
(3)跨链交易流程
& W+ @) O" W0 ?  A9 e- ^0 W1 e1 a; o# t主链到侧链2 K5 ^; p1 _6 n) e
主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链& L. g; l4 h% q4 C) r
侧链到主链+ K% d9 n7 S7 f4 Q3 S7 U' L
侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。  Y5 e5 U) @! d, Y% A
2、代码解析
, ?* R' y" i7 f- b* r( D% }跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。9 I5 Z/ b9 i  n6 @% D+ L6 e. K* b
(1)keeper启动
4 m, j' T. o. C, ?整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。
8 t* R$ N0 j$ I3 O, qfunc (m *mainchainKeeper) Run() {* i6 }! \5 ^  ^
        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)9 I  e5 C. o. o2 m$ k7 z6 V
        for ; true;
' I0 i& ^0 K& c7 Y" ^+ _Run函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。' \' z# A& S. l; L
(2)主侧链同步区块
. Z8 B9 }! p6 f2 M6 V1 ?Run函数会调用syncBlock函数同步区块。
# M0 c# ?& C2 S& [1 _2 dfunc (m *mainchainKeeper) syncBlock() (bool, error) {
  p8 B0 N% c! E3 U- Z        chain := &orm.Chain{Name: m.chainName}
: e* h  }+ O2 t# N0 F+ W# ^5 Z- x        if err := m.db.Where(chain).First(chain).Error; err != nil {9 k; L4 E7 I1 `: l# q
                return false, errors.Wrap(err, "query chain")
  y1 T! U* v7 |& H* Y        }
7 @) O' b. |& K9 q$ ?8 f        height, err := m.node.GetBlockCount()
/ ~! r  _7 ^+ Q2 n. B: M        //..
# @( x# D( w+ N        if height . \; q1 q6 x$ L; Z
这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。) J: e, y# U* ~4 }7 }5 e
height $ H' y. }6 e, ^( F3 x/ W
主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。" s- o: a' S/ m9 v/ e5 g5 n3 F
nextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)' W1 U, _4 Z; i! @3 U
9 `9 z' K0 r; U& [* j6 i
这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。
. }3 h' k' [" C; ^if nextBlock.PreviousBlockHash.String() != chain.BlockHash {
0 |% R  S; s" G( k8 j& Y8 F    //..
# ]6 I' @/ r- G; }/ G' K}$ w, r9 i3 \9 Y; _: @; v" {
在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。/ b3 Y  @1 c. K. P) ~  F
(3)区块处理
' b( l6 a$ p  P# ]6 h2 T* yprocessBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。
! Q: c0 D! {' b2 `- d7 z+ rfunc (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {
: j5 b7 a4 U# u0 ?; g        if err := m.processIssuing(block.Transactions); err != nil {1 \5 }: \" x8 K0 I8 P
                return err! `! S8 j5 t1 `" ]+ m" X
        }
5 _" n5 e1 I, C' l" D. \" @% ]        for i, tx := range block.Transactions {# u( X, h" {( m) `% @
                if m.isDepositTx(tx) {
- O8 K, m0 ]7 u9 C7 Y                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {- f* p4 r. c$ {8 ?0 l3 _
                                return err
6 q/ v" n- y; y- [* C- e) u: O+ o                        }& k. s. i4 `% S( Y8 f$ t
                }/ }5 l  @2 u1 v. y- P9 {" b2 C" I
                if m.isWithdrawalTx(tx) {
& x. @. O. O; M  c; g                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {! P/ f3 O; y" U
                                return err9 ]- G. T2 h. i0 o* m
                        }
# j* _/ U- q' }- V4 W                }. E% {& F6 O% B+ O. e
        }" J& Q: }$ e) @  v) k3 A6 [2 Z/ J
        return m.processChainInfo(chain, block); e# H- p8 i5 J2 i6 s/ E# X3 o
}
) w  S' y5 i% I$ B' O在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。# x) z. }0 m: T" g$ o
m.assetStore.Add(&orm.Asset{
$ z  A  k' n5 m- iAssetID:           assetID.String(),
4 \! ]; i+ H# x# pIssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),
7 ^; ]; o) x+ b% XVMVersion:         inp.VMVersion,
6 G% c5 J" E  {: iRawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),
  g! q- I4 J: P+ E  ?5 R! J})* S# f/ C; x! S8 C4 m. e- W
在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。
# m, F: n% x* R& U/ X$ P# bfunc (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {
' |1 B- f7 w7 S. e6 H$ o        for _, output := range tx.Outputs {5 |- O/ Y3 R8 D! {# K1 a
                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {3 y; o  W( Y6 g0 }, l! A* D! Y  Z
                        return true& u" N5 F0 \' y; |0 t
                }! ~/ d: L2 s. ?7 I6 @& P
        }( G4 K2 n# M4 p6 [  @
        return false0 O& _6 a$ V7 O
}3 l6 {$ B* k& _
func (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {  M- g# M- E# ]& E& I
        for _, input := range tx.Inputs {  Q' x  K; n: ~6 Y; P4 v3 W
                if bytes.Equal(input.ControlProgram(), m.fedProg) {
$ |4 u# u8 r' I0 x8 |- i                        return true4 U$ E" n* E6 l$ X
                }0 N6 _' l1 C. k  c
        }
: P' G) ?6 k- E        return false
& U! B) I( z2 J7 n) y! H, q}
- i6 o+ M/ ^+ o/ `" i3 V0 `看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。# v5 q; L5 U* H( T4 u3 I& a2 d2 H
type mainchainKeeper struct {
" T9 o. @3 G, t8 @4 o# y        cfg        *config.Chain/ w4 t+ y0 a0 W
        db         *gorm.DB1 \  i5 n8 }; X4 n" k! A$ t
        node       *service.Node% P& F$ U/ J& Y& Z" ~5 y6 m( f  {7 h- X
        chainName  string0 }! _' X$ Y7 z
        assetStore *database.AssetStore4 j- c* p# I! Y/ `1 I9 W
        fedProg    []byte& d. f& H' m! o1 S8 @5 M; s
}, G% T" p" v) X' k& [. M
(4)跨链交易(主链到侧链的deposit)处理0 i1 n; J& W3 g0 ~- U, c' E) ^
这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。5 x6 e) S& B, W. P  B1 D- p
func (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {
& T( ~+ p1 `2 ^        //..
6 y$ ?" m5 Z9 v& ]        rawTx, err := tx.MarshalText()
8 l0 z4 ~/ W$ X# m* m3 s        if err != nil {
# p" m' v; K; P% e6 i8 @                return err
: z* \) P: `' u1 q3 q        }
" u. b; Z5 f# U' U; g        ormTx := &orm.CrossTransaction{
* P- D: M0 n( Y5 U/ a9 c              //..
/ V  `' h% r) W. U, @        }6 c* C# K0 Z- a# w
        if err := m.db.Create(ormTx).Error; err != nil {: G9 H* k2 @% S3 X9 z6 B& C
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))( {: k/ l9 R+ ?, D% o
        }  {% N9 M# F! B
        statusFail := txStatus.VerifyStatus[txIndex].StatusFail
( ^! F. I9 i0 a& a        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)" v! w3 \  M; v/ ]3 A9 ]8 z
        if err != nil {7 L/ P* f) g2 w+ [$ n5 u( _( D/ _1 k
                return err7 {/ x6 ]% l# t5 `: v( Z# p3 X6 m% W* L
        }9 {1 H  O3 P+ S2 p3 n- d
        for _, input := range crossChainInputs {1 a; {( C. F4 Q  P6 D4 h2 c
                if err := m.db.Create(input).Error; err != nil {
4 {4 C( d8 D9 C                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
* O; x! q: |6 E( W9 K# v, q                }" _& n" s  @+ h& ^, t
        }. p5 H* Z/ i  M/ o: k: [/ f$ h
        return nil3 [6 ^) h* C( p2 ~+ C0 i
}+ L) b1 m  c! }! N" Z
这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。
! K& k4 J- D4 d9 FormTx := &orm.CrossTransaction{
0 o, r# T3 D% w* I, r                ChainID:              chain.ID,  v1 Q3 Y# W3 `0 `8 H  t
                SourceBlockHeight:    block.Height,
1 C- M! M0 t8 u/ W* F* J                SourceBlockTimestamp: block.Timestamp,
0 ?- y' q1 a* ^+ R/ s                SourceBlockHash:      blockHash.String(),, ]9 S8 A4 f( I! ]2 m
                SourceTxIndex:        txIndex,
0 F! H( c; g5 Z                SourceMuxID:          muxID.String()," O0 N/ h* B" }! p* P  p  j4 t/ Z% e) z
                SourceTxHash:         tx.ID.String(),
$ [. ^' {' S( r* L1 |7 O( s0 A                SourceRawTransaction: string(rawTx),- R" x  |; e6 |5 V- b9 x' z
                DestBlockHeight:      sql.NullInt64{Valid: false},
" C4 F5 o8 x5 G% B3 p0 O                DestBlockTimestamp:   sql.NullInt64{Valid: false},
4 K4 p  y) @: U0 {8 ]! V2 f8 |                DestBlockHash:        sql.NullString{Valid: false},
% Q* j: @# g! {5 z  {9 i                DestTxIndex:          sql.NullInt64{Valid: false},9 x0 ^  T7 O4 J1 v( `) r% w0 ?$ y$ c
                DestTxHash:           sql.NullString{Valid: false},
' O5 A# v0 Z% e& e; w: P7 R                Status:               common.CrossTxPendingStatus,( l, v' J5 x2 C* @4 A" |
        }' f+ T, H1 ~5 q8 O( \5 N
创建这笔跨链交易后,它会将交易存入数据库中。4 [/ @6 C" m5 m
if err := m.db.Create(ormTx).Error; err != nil {1 d8 j. F, z+ L
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
; M2 a2 c1 S( `. i4 X}) h$ D9 W$ z$ K8 H; {# K! j7 _
在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。. B7 Z) z& ]( L  _1 t1 N
func (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {
: X" ~8 M# ^. M; b5 D' ?! j% y        //..
( t- ?1 L' w% g9 x$ T        switch {1 [9 H" R1 L8 N% k6 _$ T5 e) D
        case segwit.IsP2WPKHScript(prog):9 m1 D8 S( j3 x9 t/ z+ h. S
                //..# L- c1 t0 M' P  l" U4 S2 l. K
        case segwit.IsP2WSHScript(prog):
0 |% G( f! {& Z, @* G/ R                //..) M/ M; d5 I7 j8 T; X4 |
        }9 ?; a  G, W4 k( m% r6 s1 A
        reqs := []*orm.CrossTransactionReq{}, l1 q" ~! q, X+ H, `
        for i, rawOutput := range tx.Outputs {
! _1 e- D0 G4 \# `, ^9 G1 O  N' ^; A                //..* l( F, a# P' o( f, ]( f6 v2 j
                req := &orm.CrossTransactionReq{
! v% {" V# X+ N. M                        //..
+ u  V1 a- }5 p' O6 K                }
- @% _+ C" E( V                reqs = append(reqs, req)% q, h* S$ f( l9 c) f. y
        }
, y3 {7 k$ J8 @  z0 {7 v        return reqs, nil0 G  @# S- K/ |) P
}
+ V% F7 J2 A) j# b5 F8 _很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。
6 g1 R7 z: ^+ g0 r/ Xswitch {
; y: r) n, ~. Q/ t$ o        case segwit.IsP2WPKHScript(prog):
- t, w+ b% g) [9 p7 R3 s! s                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
# W) e4 }, I' r2 M- t7 H; R                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)
  x* ?" ^' Q' S6 S8 V                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams)
+ k5 n. z7 n; ~, |% l' w                }
6 O- H8 X& w) w4 h9 u        case segwit.IsP2WSHScript(prog):
# i, V+ a: `: j1 }                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
1 D% j$ _: C" g                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)8 ~8 X- v" h) ^7 c5 x  {
                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)
  I* d8 j6 a" e# {5 X                }
$ ]' D. W4 a4 ?  Q1 W. O1 L        }
; f5 M3 ~+ m8 e/ q2 H在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。
7 n# K, q# H" |+ @, Breq := &orm.CrossTransactionReq{
3 t: ^5 I/ c5 G4 k, |   CrossTransactionID: crossTransactionID,( S# _/ }# ]/ w
   SourcePos:          uint64(i),
& Z$ W5 t7 m7 l5 ~7 \+ U+ x, g( y0 H   AssetID:            asset.ID,* v& k" v. x" p; q: E
   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount,
- |' H0 G3 B2 I1 ]; W0 Q" R" e* m. d* |0 B   Script:             script,6 m9 B$ h& M4 L- j0 q; e
   FromAddress:        fromAddress,; ]* V8 H& o, J, m6 [+ [7 z* y
   ToAddress:          toAddress,
8 q) @) j' a4 x) r2 o% C/ M+ ]. v   }
+ f& A4 u% t" z: G9 Q* s9 z' [2 {创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。7 {% K) `. [, e: B! x
for _, input := range crossChainInputs {3 {/ C+ Q- I! L; k
                if err := m.db.Create(input).Error; err != nil {) W( q' [/ |. c& c
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))* \& a: }" h; N
                }
/ P  s. }: U4 i* j8 c  u6 o$ B8 V4 J}
! ]1 ^/ E: r* k9 |3 z到这里,对主链到侧链的deposit已经处理完毕。/ |) N7 _. d6 H
(5)跨链交易(侧链到主链的withdraw)交易处理2 \* h* ]7 ]2 q6 c6 |" \
这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。
) Z) U: D, F! O: G% D3、跨链优缺点
3 L; F% S0 J8 F! \5 v8 D优点+ S. A1 H7 y; d! R; V, j( h
(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。6 B7 u# t8 |! d8 l, ]
(2) 可以根据不同需求实现侧链,满足多种场景/ S5 h) y2 t8 n$ G9 f
缺点  d# t6 Z5 c# x' ]; i1 b  `
(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右
6 t2 i% x" g3 u) t% ?(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大& _9 ]' t# ?. o$ `) [
(3) 只支持资产跨链,不支持跨链智能合约调用$ q) c) h, e* P$ _% [' G' {  r
4、跨链模型平行对比Cosmos
. i1 }9 D4 Z. N# q" \可扩展性- W/ E" \9 Q8 @1 T
bystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。7 c" ^9 d: d  j) b# a9 S
代码开发进度9 v& E( a$ D" ^0 Y
vapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。
" ~0 w+ c4 G) D8 A1 g跨链模型- N" a6 C" g2 \) p7 k
vapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。' K* |; F! Q' v* i3 \8 g8 u
5、参考建议; {" x, a  u5 `3 L  Z
侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1