Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
138 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。5 m$ m  G8 U- c& @

% I% y( f" N2 C5 T: R% E; ]Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。/ W& m/ u: Q) ?1 Z; Q- F( s
主侧链协同工作模型4 I! c9 c% K! c

0 o  G" [: b9 K6 K5 i& N5 m( a1、技术细节
; d) A: i0 [- @9 a5 l2 W- xPOW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。4 q% D3 t1 s3 w5 z1 i  i
而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求
, N1 E7 a! c# s: j! c1 O( d(1)跨链模型架构$ L4 i6 n% n) [) ^
在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。% D% A- Z) L; y( V0 U/ S. P
(2)节点类型
0 L: R7 |$ M% b4 \* G: a跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。
7 Q1 }" {5 ~8 U# ~(3)跨链交易流程
3 @: o) r& R* D2 b主链到侧链! @6 ?( r% c  b9 r
主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链3 F6 D5 I( t% \& I
侧链到主链
# D1 z# K& d9 F! y) h侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。+ X, }7 ~& E" T! z3 g5 k
2、代码解析
# E  X% A) Z( X跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。, |2 T* E+ x# M0 ]3 @5 n/ [1 q
(1)keeper启动) h* Y( L' {1 @# F
整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。; {8 t8 t8 u! y3 K0 o5 ?
func (m *mainchainKeeper) Run() {1 W& P% c% r/ w9 n$ D9 L" ~
        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)
9 M5 K& u; s7 P0 P* R        for ; true;
, q$ d: Y% J9 {0 K1 [% BRun函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。
; Z$ S" E1 u7 [8 E3 ](2)主侧链同步区块# N& r, r1 r5 F- ^$ O" D# n2 i/ \0 `# ?
Run函数会调用syncBlock函数同步区块。
# E. `4 P  I5 v& e; Lfunc (m *mainchainKeeper) syncBlock() (bool, error) {
+ ]% y* d* o& E  j  X! k) w        chain := &orm.Chain{Name: m.chainName}/ k# b- z. h1 T2 x' V  R3 _
        if err := m.db.Where(chain).First(chain).Error; err != nil {
0 i3 U1 J4 E" ?3 e+ n                return false, errors.Wrap(err, "query chain")
/ N7 x8 L/ ?3 K# ]) t        }
8 W. B! L% X9 y        height, err := m.node.GetBlockCount()
. L. L1 l6 m# ~4 b  k) k        //..
* P* ?4 x0 g+ R+ W7 K) ^        if height
6 r5 b! `- [0 m2 u4 r4 F' q这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。
8 C5 _6 [$ B0 {& H2 j% Rheight 6 \0 H/ J+ f( B% O
主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。
* }- A9 m0 N' O5 d2 `  bnextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)
5 N# C( e5 f0 l8 Y5 F, u3 H
7 D8 g# x# ^9 A# f' e这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。
3 ?6 t, `/ ~& Y: @, o, yif nextBlock.PreviousBlockHash.String() != chain.BlockHash {" `; w5 g& J) m8 W2 k$ ~& d
    //..
# D/ J! _; j; a2 F# G}/ e- K: F- B/ O3 X+ \
在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。
: ]2 ?) L9 b" g  N9 q: q(3)区块处理; O- z; K, H* k
processBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。
6 }; a9 ^' d/ v& w9 G( m* lfunc (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {
4 q( Z+ V- i6 M; g- q7 ~+ R        if err := m.processIssuing(block.Transactions); err != nil {# p  ~  Y( R- H- T/ _) Z
                return err
4 O  Q3 `! F) d        }
' ~/ I+ `$ ]( c* q$ C2 J! j2 S        for i, tx := range block.Transactions {' q6 b5 C6 m; r9 x- r9 f
                if m.isDepositTx(tx) {
1 k$ I! t; f5 ~- k, W                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {
; n& O3 z3 f' v% r9 t1 L. C                                return err
/ U7 j& g/ j  c3 a% x3 @! ?9 l                        }/ w4 t+ o' o* ]
                }% C4 e3 g2 F$ k
                if m.isWithdrawalTx(tx) {
9 f) S8 H- v: L* K% C6 V+ L1 w# E                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {
* [- ]9 d1 B( v! L1 V3 R                                return err
& H1 S! e  K' d/ L) x, f                        }; |  _# h- Z4 j) s9 c
                }  S: E! G! }  }3 y' Y: F
        }2 }- p3 D. ]" b5 D% o4 Y9 Z) H8 @
        return m.processChainInfo(chain, block)/ \9 _. l7 f' B' [# T; ~
}! e/ H) ]7 E( k% ^0 T0 Y
在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。9 g2 W! m2 y3 T7 O4 r
m.assetStore.Add(&orm.Asset{
2 J) `, c4 K% ^1 u# BAssetID:           assetID.String(),
9 y7 R; v/ N5 d$ v2 J1 i( RIssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),2 `/ B3 E& j3 P1 b) g0 [/ W+ s
VMVersion:         inp.VMVersion,  B( {- `% w" F" t/ H* a. ?! y
RawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),* v6 S! H8 i5 E
})3 `0 p) |/ [# H  `! ]! i. \! p
在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。
4 A7 y) H: ?5 R% D- xfunc (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {
" C( X4 p: ~' E# A        for _, output := range tx.Outputs {! ~9 y3 q* `( g% p" s
                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {- n; y: D3 ?( `$ W6 m
                        return true
+ @7 x. d2 f, _                }) o, {8 ^5 u( @8 r
        }
7 A' K9 U# L! l8 ~* A        return false) b( F3 }3 g: W( G7 U
}
5 ^" U6 ^  \, U! A3 cfunc (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {$ w* k+ B7 G, y4 U% e7 C
        for _, input := range tx.Inputs {
! J( v% a7 v, ]                if bytes.Equal(input.ControlProgram(), m.fedProg) {3 S. g1 F( @) u# D
                        return true
% W! K+ u& S: K* d( b6 }% I                }
4 {9 O# z6 h+ p/ b8 n) V        }
- {9 l! ?4 Z8 ^* c( T& ^( p& B        return false% c  T! l  u  ]; N1 ~
}. W* b& E6 C# r
看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。7 M: D5 f2 o4 q9 z) v- q
type mainchainKeeper struct {
) z2 b3 k+ G7 w8 N" z7 X, a        cfg        *config.Chain* q: l3 r; c2 L0 h& |4 j
        db         *gorm.DB6 i9 @; j2 ~& L+ ^
        node       *service.Node7 {6 }7 X7 o& W  s# X# E
        chainName  string: {$ S7 E, Y/ y
        assetStore *database.AssetStore
5 P& I1 D9 R+ u        fedProg    []byte1 H6 W" o. q- ?
}
& y% F0 n8 d7 `(4)跨链交易(主链到侧链的deposit)处理* A: Q$ J4 K7 g1 J6 T% e) i
这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。. ^# j. s$ w7 o2 z8 T7 l
func (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {
/ O& E; h. @1 W4 ^* Z! p3 x: w9 Q1 r        //..
# p- k4 U% U2 `        rawTx, err := tx.MarshalText()
2 l) s; z! k' x7 ^! X7 y        if err != nil {# }4 T0 _  A% c: t8 a  N* E
                return err
( p" {  p' Y: ?  Q; z8 w        }' ^! j/ P8 j( X! E
        ormTx := &orm.CrossTransaction{) l) f! I4 @% w9 @
              //..9 B4 [2 x$ i8 f2 J2 D
        }: u* M1 X; ^) Y! ?/ L" Q/ ]; u
        if err := m.db.Create(ormTx).Error; err != nil {/ W& c# K, g* g1 N8 m/ }
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String())); L- u; W0 T$ t* o! g
        }
$ ^# j% ^/ ]5 Y0 B2 ^4 h9 U        statusFail := txStatus.VerifyStatus[txIndex].StatusFail7 @; G7 M- o  R/ Q1 x
        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)) @) Q; x" A7 p' K, ]2 I' e  b; O2 c2 k
        if err != nil {* k8 J# s4 {; T7 g& y. L
                return err* h: X. H/ `' Y# H" |* a3 p  X
        }2 v, C  j2 v7 |$ }& T' m" Y* y  Z
        for _, input := range crossChainInputs {3 ^& Y/ X) h( d# K* L6 E
                if err := m.db.Create(input).Error; err != nil {. U2 i5 }( N  M. ?) ]3 s  ~4 P
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))0 k; W9 @  R4 P& t6 [' u2 q
                }4 g9 A3 S/ w1 L
        }7 h. J8 ^' R) H7 P
        return nil  T) K. z- V7 F* G$ \$ w
}3 B$ Q/ I7 Z1 i# M0 X0 @1 @0 z1 C
这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。* l# k) ?, w$ o- a% D; Z& {1 ~1 y, P
ormTx := &orm.CrossTransaction{% r+ a5 R$ B3 G. v( o+ O* D
                ChainID:              chain.ID,
( v: _7 O8 {' F, k2 B                SourceBlockHeight:    block.Height,+ r4 m- L- p& D0 T( @) y: h
                SourceBlockTimestamp: block.Timestamp,
, ?8 s: ~( W, I6 f                SourceBlockHash:      blockHash.String(),6 \7 ]" x: x7 t
                SourceTxIndex:        txIndex,
3 H$ `  q- L7 Y* W' R. z                SourceMuxID:          muxID.String(),, b! w9 B/ w+ |! z# }1 l$ C! k
                SourceTxHash:         tx.ID.String(),
6 L7 U: v( T1 X. U                SourceRawTransaction: string(rawTx),
) x, \) C6 J) L% J                DestBlockHeight:      sql.NullInt64{Valid: false},
9 J5 A' U9 z. O. s1 Z' f: X0 T                DestBlockTimestamp:   sql.NullInt64{Valid: false},' a' k# }  s/ o& C' D" |
                DestBlockHash:        sql.NullString{Valid: false},& `, s" x6 W% i. t) C  f
                DestTxIndex:          sql.NullInt64{Valid: false},- y2 I" v' P/ Q* J9 \
                DestTxHash:           sql.NullString{Valid: false},# D9 K9 q! W1 N2 n9 l* j/ z0 y! C: Y
                Status:               common.CrossTxPendingStatus,
# a# |- Y* T, a. v, O( n        }
0 L) [5 [7 ^$ \# A创建这笔跨链交易后,它会将交易存入数据库中。% e+ e( k7 \& c. H, K* O
if err := m.db.Create(ormTx).Error; err != nil {
* I8 Y) c3 j; G1 D1 @( a                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
- }2 @* \0 g. j+ C" R4 E}
" L4 Y5 \" v+ I, J+ P) }: I' g- U+ E在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。
. A% g  S% k# l. y: mfunc (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {; u5 X" w% g; l1 C& @
        //..
6 X# y; s9 D( D6 ]( b' S  e" H+ c        switch {
) S; o- @: B( I" a3 Q) ?$ G$ ~2 M        case segwit.IsP2WPKHScript(prog):
' o, E7 \3 H$ s: ]+ h4 ^' C                //..
% {$ ^( d( _5 `, P% p. m        case segwit.IsP2WSHScript(prog):/ M4 b  H8 A- n! v" D! x
                //..- ~2 R1 t4 h6 ~5 }
        }
0 |8 |7 s; U: G: Z; t        reqs := []*orm.CrossTransactionReq{}( a2 g1 @9 L7 s( L) [- ~! F) x
        for i, rawOutput := range tx.Outputs {* B. j8 J, C2 I7 s2 P; {
                //..
' C. ?  e3 {" Y6 e# r8 E7 F' C- p                req := &orm.CrossTransactionReq{2 T$ `9 K* N  h  ?: u! `* p
                        //..8 `& G' i8 \4 c/ b  n# D
                }2 x/ y0 L; ?9 ~
                reqs = append(reqs, req)
/ o1 }" T6 r5 w" C) S7 P9 f6 F        }
- W; t: S2 {/ y, J/ z        return reqs, nil
, G* ]7 V; j2 N+ S! n2 u7 e}" s6 H, {  W8 j5 a$ I5 R& t5 z" m
很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。+ x+ U5 W6 D' k9 \* P& N, M5 j
switch {
: @6 k4 N" @# ^+ K2 _9 ?/ L, [        case segwit.IsP2WPKHScript(prog):. g! G2 R* U! m6 b; V/ E9 D3 e
                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
0 p) d6 y; X" T' U                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)( v/ Q3 T+ S2 x, s' i7 U1 a
                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams)" G: w2 Q% ~, N) `/ A2 z
                }
1 r& A% ?# f" N# L& H  O; _        case segwit.IsP2WSHScript(prog):; C& r0 k& R% p3 j- H( |+ l) l
                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
2 Z$ U7 X+ i% X! Y: c/ P                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)+ S8 t3 [" `/ a& V2 ^  o, ^: ?
                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)
3 n  y& O4 o3 C: N, ]2 L! r                }
5 c9 V! R7 L* d* ^& e: F        }
& I9 d6 w) P( M6 p在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。
& h  L( u: X, r/ _: j# a- oreq := &orm.CrossTransactionReq{1 J2 t2 \. O$ q
   CrossTransactionID: crossTransactionID,
5 }8 Y  g3 m' v, i( G# s   SourcePos:          uint64(i),- r  }8 q" z5 p3 Y
   AssetID:            asset.ID,/ r6 W. m% ]( i
   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount,
% t9 s: J7 u% J4 S  y   Script:             script,
0 _) g8 @; z8 v$ @1 [   FromAddress:        fromAddress,. O7 ^# J* [' l) y$ O, G
   ToAddress:          toAddress,' R  o" s7 w3 O* i) s6 X, I
   }
, B2 g1 _1 h! X$ U创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。+ d) i; Y1 {2 F: L  F9 |
for _, input := range crossChainInputs {6 W  l$ |6 @: `7 Q( p
                if err := m.db.Create(input).Error; err != nil {9 ^; I2 w  u5 o7 n5 A7 k
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos)): K* s) |  J) a2 J+ F
                }" K8 x4 r- o% x) ]2 s
}3 M. @, i" C& Y7 O& r) L+ x) q
到这里,对主链到侧链的deposit已经处理完毕。) W/ }2 h. q7 b9 Z4 ^0 j: P
(5)跨链交易(侧链到主链的withdraw)交易处理
. v9 j! I: d4 I4 O+ i这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。6 \3 z  X! s9 O6 f* Y% ?: q
3、跨链优缺点$ w2 ]" _4 H4 [) D; N' X2 p6 _, r
优点' z$ F; s& M- _- T" W
(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。/ D$ U3 F$ D! B6 {1 g* ]3 |5 q  e
(2) 可以根据不同需求实现侧链,满足多种场景( B# g' o8 d+ b" l: T/ ^6 k& @
缺点9 n9 n% Z* P  s; m, l2 S2 o
(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右
8 L, W  L. O9 G0 R& T6 d; M1 G(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大# F. H1 X3 V* Y7 l
(3) 只支持资产跨链,不支持跨链智能合约调用
: w4 a9 r7 U# q. e# F( V& [4、跨链模型平行对比Cosmos- }* d$ C& i% t3 n) t, Q# g3 P
可扩展性0 b+ _2 d/ S7 G$ H9 `
bystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。
5 [* ]# q" P" [9 [代码开发进度% ^7 `1 O: q" q; \6 H! Y
vapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。
$ D' Y; [' [# L) Z% d跨链模型
9 P8 u$ {6 ^" P+ ?vapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。
+ n- |# B) L# x4 |+ c' _  ~; N" r1 n) l5、参考建议
6 F/ W( z! w( y+ Z: |侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1