Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
222 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。, l9 F1 D, ]$ j  V( k/ b9 [

9 g( y& B, h* A2 l8 vVapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。
1 y6 o( e% z7 p; L* d主侧链协同工作模型# r# r$ f- v5 g  _  \4 f5 I

1 k0 {3 L9 x  J4 ~; D1、技术细节
/ `! S# p# C- F  b8 w! Q3 YPOW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。! w1 Z8 A1 Z# V, D7 N' j9 T, G
而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求: M# f! l/ Z3 u* b5 N: y% u  _% q
(1)跨链模型架构
& V( n- s+ p- p% b. w在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。3 x7 K* q8 S# P8 o/ h
(2)节点类型
5 p8 z; V$ D/ \8 ~6 n) X: b跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。* R4 E$ Z3 \( m2 o. Q) ?
(3)跨链交易流程
. ^, q& P) s- ^9 D/ i5 Z主链到侧链
6 B0 \$ H" i9 L; x8 k主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链
) d  |) Q8 {+ i8 f$ a侧链到主链
7 k3 U6 L2 F8 A3 ^侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。. s( B4 l" j+ S' L* h+ k
2、代码解析( y/ @0 G* E1 N5 B* n! W" \; k1 e
跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。
+ @6 }* r$ N' Z/ ?/ Y* s(1)keeper启动9 Z7 f. P" w( y1 ~2 B8 _" j1 B0 q
整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。( j: Z# h. z) f
func (m *mainchainKeeper) Run() {
; k8 p' S7 j8 f+ L* C        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)
3 I2 {) t2 Q0 T% f* L        for ; true;
2 f: M+ T2 @! D% D+ rRun函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。4 r) j3 h" f6 C+ Z) Q# @& h
(2)主侧链同步区块
7 f9 g$ `7 G- |, YRun函数会调用syncBlock函数同步区块。" x1 v2 H3 z& E5 |+ j$ m5 G
func (m *mainchainKeeper) syncBlock() (bool, error) {
9 C% Z% X6 ?4 z( k        chain := &orm.Chain{Name: m.chainName}* X& V  {$ g$ S' ?+ O; o$ ^
        if err := m.db.Where(chain).First(chain).Error; err != nil {
- ?4 X! a) v# T: @4 L                return false, errors.Wrap(err, "query chain")
  s& `8 }0 _1 `* a        }, r7 o7 |' I1 A0 P1 |
        height, err := m.node.GetBlockCount()
* {2 L* R7 M/ _        //..
" I) U  R# X0 e        if height 0 ^' q! w: e9 {; T4 z$ J+ i5 f+ u) ?( o
这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。- v' l8 q$ S; d  B+ G) @: l- M
height
1 n4 s& B  r1 f2 A主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。: ^& m7 X' L2 y' @( E
nextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)
+ K* G1 I) K9 t$ v" e1 Q& ]6 D3 D8 n4 |( h/ }  o
这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。% `6 G( J$ l7 ?" y/ B: D
if nextBlock.PreviousBlockHash.String() != chain.BlockHash {
) M4 d7 N# Y! w( L/ t    //..
/ `7 i3 h4 H% P}& C$ s2 e! F; Z' a& Q
在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。
4 e' b. W7 {+ I/ ^(3)区块处理' H7 `3 l5 t! E$ T- n
processBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。' H2 K$ a5 r. m
func (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {) n: n* ~: Q7 w" @
        if err := m.processIssuing(block.Transactions); err != nil {
& G3 f) R/ {9 s) v6 a                return err
- Q/ u2 J  C, l$ f. v( Q* p" d        }+ S; e9 l9 D, A7 U+ m1 K
        for i, tx := range block.Transactions {' x0 S5 {8 Z  x* u/ [/ s+ H
                if m.isDepositTx(tx) {
* N, D. Y8 f" @8 `& V4 ^                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {
3 x& ]) h4 g, v/ H6 k% Q2 P! q                                return err& w9 @' ?/ B4 P* s! }8 x
                        }# ^' h/ \- z! y/ f& l
                }; J- j8 ^% R, q8 ~9 j1 Z' y2 N
                if m.isWithdrawalTx(tx) {
. ~; X) R) J0 `- b! K0 ^4 V4 Q                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {
: n3 E1 X+ J0 o- s8 t/ U                                return err  G, Y* Y# J  J
                        }
$ n% V7 _9 A4 m7 j2 R- I4 i  ^                }
- q; [$ I! \8 V4 Y: P- l/ ^3 G        }
8 ^; ?7 s7 ~9 \  g7 o        return m.processChainInfo(chain, block), ], E2 ?: T$ S3 |# O) z
}
) W# Q0 Z+ s, `0 z1 K% Z在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。
+ L; E8 q7 F7 dm.assetStore.Add(&orm.Asset{) M: Z) m/ d' Q, t
AssetID:           assetID.String(),
9 `1 c& i& d. O/ XIssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),
3 o9 ~: k( g2 i) J  LVMVersion:         inp.VMVersion,  [/ \/ i& c* u! D
RawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),
" O; J) X/ U8 F})
4 u2 o* q) R* ?& ]  |/ l! s% C在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。2 a2 U9 P" G2 V! ^1 b7 h: }: d
func (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {+ a* X) Q1 C; c% G3 f6 F; y5 v
        for _, output := range tx.Outputs {
) m9 _( m& W2 g6 \9 g5 n                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {1 t- q: h/ m  j; r# S+ a0 z
                        return true
, o9 x7 r3 ?7 [7 r+ X6 E                }
% \4 Y4 @: C( Q( W8 b3 d        }- f1 F" P& A2 y9 H$ H$ C
        return false
0 x/ n+ s, i/ E8 ]& O! h}# Q5 w$ C1 P1 w
func (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {
0 y. c8 Z% d. ~4 q  P! b% b        for _, input := range tx.Inputs {5 `8 @3 j6 g( n0 b3 {* [2 I% r
                if bytes.Equal(input.ControlProgram(), m.fedProg) {3 @: ?" V" V  u2 k6 s1 b# X! S
                        return true$ d7 f. C+ Y% V
                }1 U: @3 z. `" c3 ]! T2 n# T# _
        }" ~5 a0 d6 f0 P
        return false" K5 Q: M9 c: K# \- X
}' y8 F! O. ]" v) Z9 k+ J9 n' b
看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。  E0 U' O5 x4 u" a* l
type mainchainKeeper struct {
5 B$ U7 P# U0 k8 C        cfg        *config.Chain3 w, J( }& c2 N
        db         *gorm.DB
, d4 K$ B+ T% \1 L) B! j4 p+ Y        node       *service.Node- y& q' u! a: p3 V) ]' h# a
        chainName  string
3 Y6 o7 P/ G. a7 l& D# S        assetStore *database.AssetStore+ f: Y6 m3 C/ M. Y3 N7 h
        fedProg    []byte  f- C/ L( w6 X! ~
}
  S1 H  N( A  D# k9 m. F(4)跨链交易(主链到侧链的deposit)处理& s7 b! x% F% v/ d1 E3 J0 f
这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。
# p1 |% v* X+ D2 E: ffunc (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {
9 c" h2 [/ v" q" S2 {" G        //..
" [- M6 ?' m1 q$ |! J8 N        rawTx, err := tx.MarshalText()5 v7 m& j! X& _+ ]: r, V
        if err != nil {& |" @1 a3 n: P+ f: I7 w8 i
                return err9 ^' h0 |. b% ?' X. A
        }4 T$ t9 K  E5 \
        ormTx := &orm.CrossTransaction{7 K4 V) h' E+ f' A: E. C
              //..
+ A4 l1 ]$ u& g( K9 a- q        }. ^% F7 t/ r5 x3 Q( O  b
        if err := m.db.Create(ormTx).Error; err != nil {( u: t7 `7 S3 h; N
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))3 i( _5 X$ w. _$ p! Z  F! J
        }, F* Q+ ?0 A. X9 H- O+ R" B( _
        statusFail := txStatus.VerifyStatus[txIndex].StatusFail8 I* `; d- S  O5 x
        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)0 H# m3 |  ]3 y8 F, j
        if err != nil {* X  [9 L: N4 [" m# `; t9 e8 _
                return err
$ E/ ]6 j* u# X! @        }$ K( v0 g% @7 O3 V* ?, _" N
        for _, input := range crossChainInputs {9 p- e4 R- L' v: A( S) L; v' b
                if err := m.db.Create(input).Error; err != nil {4 @& r6 F$ v' A) ^
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))& z5 Q5 @" u& t4 S
                }
; ?# e+ ^! N9 e# e        }
3 G) p5 g/ H. L& H* ?8 P        return nil
3 O: \" O7 s& b! \5 {! T% |}! G- {+ a, R& }2 [7 d* i7 v
这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。9 {4 Y* f5 \# L( p( A* X
ormTx := &orm.CrossTransaction{
: x# C% |% q5 [" h                ChainID:              chain.ID,
' O* E7 S8 D+ Y                SourceBlockHeight:    block.Height,, i, T( A9 Y9 {# ^, f: }: y: ~2 u- `
                SourceBlockTimestamp: block.Timestamp,6 A8 `+ v/ a8 n0 H4 ^
                SourceBlockHash:      blockHash.String(),5 u0 M% z3 J! h% Z0 i8 Q8 l
                SourceTxIndex:        txIndex,
4 c0 i* }5 j6 z                SourceMuxID:          muxID.String(),
# K8 u7 t% j: e5 G/ e, M$ p5 ]                SourceTxHash:         tx.ID.String(),$ |1 V5 c# N8 \" k; S, H
                SourceRawTransaction: string(rawTx),  H: O, r8 _4 N2 H/ v
                DestBlockHeight:      sql.NullInt64{Valid: false},( L; t9 b7 V! L: R8 f
                DestBlockTimestamp:   sql.NullInt64{Valid: false},# [5 v- _% ~5 \3 |2 ~6 c' Z6 n. ]
                DestBlockHash:        sql.NullString{Valid: false},
0 h5 U! S" O5 C/ X( M6 C1 i6 P, a& u: B7 A                DestTxIndex:          sql.NullInt64{Valid: false},( x$ e; Z2 T4 |- d
                DestTxHash:           sql.NullString{Valid: false},
# a6 K: V5 E& T4 d) ?$ |                Status:               common.CrossTxPendingStatus,
3 b+ b  }4 i7 h+ C9 q        }
9 U' F# C) ~* z- K. t创建这笔跨链交易后,它会将交易存入数据库中。
& J5 v% P- u8 J+ U7 V: `) uif err := m.db.Create(ormTx).Error; err != nil {
  L* [+ b1 u! B4 a/ z+ x                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
9 v. q; J6 U5 K2 ?  \}- L0 d+ W' N+ b& N) b. D
在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。
% o+ M* t) Z( sfunc (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {
- y3 ~6 T8 T8 h5 P        //..9 `$ y# V+ K% {5 Y4 D; U
        switch {" S5 f# T0 a# |
        case segwit.IsP2WPKHScript(prog):$ \7 ?) _8 x9 ~' b+ L3 T& t
                //..
  g' m5 d  l6 I  g9 ?( G4 Y! i3 E        case segwit.IsP2WSHScript(prog):" Z1 V% o/ R7 {& t6 W/ E5 r, S! V
                //..
$ K- u+ y$ w  e. J3 @+ ]1 N        }6 l; O3 K  Z' m) u- o2 i+ A
        reqs := []*orm.CrossTransactionReq{}. ^: p  n9 K9 N7 P4 R( A7 O3 H
        for i, rawOutput := range tx.Outputs {  _6 L6 r* t0 |
                //..
% |3 ?& O/ [2 T) G+ e" t                req := &orm.CrossTransactionReq{* p2 j$ a( \; h# K. h% \' |% Q
                        //..
5 f* ^1 ?$ X8 _/ B, y9 ]( u, y) N                }! m$ r8 y* K# z5 u5 U! S6 C" A
                reqs = append(reqs, req)+ N/ R' N7 H8 T4 D+ P1 F4 R* u, D
        }5 W6 f6 x: c" b% R% a! G7 R4 t
        return reqs, nil. F% _( o; B3 U- f" j; e
}- b2 Y8 ^& X8 I  r% }4 i
很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。4 e3 e4 R( ?2 R9 X
switch {% Z1 d8 i2 F7 ], u) \/ ~
        case segwit.IsP2WPKHScript(prog):
: W% w9 C; W3 ^" o+ N& E* ?6 E                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
+ s  q, h" c" \' {7 _5 a                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)
5 O$ B5 p# O' b1 h, L5 d                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams)& l1 Z$ w5 N' Y; i
                }
5 d1 k3 H) C* r0 V( K, E        case segwit.IsP2WSHScript(prog):2 z9 D1 A7 _( K& W2 v+ Y( q
                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
" S) I1 d* {- `5 H                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)
8 L$ @' ~* g4 h: L+ e  |                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)
$ R2 W3 e( z, r' D                }
3 h1 i0 Q+ ?# ]' b        }; N- g, I) U- t. C
在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。
" k" P9 G* D! H1 T$ ureq := &orm.CrossTransactionReq{  f5 R( j% n8 F
   CrossTransactionID: crossTransactionID,
$ G7 T7 W( o) S, S) ^* K- N4 H% A   SourcePos:          uint64(i),
' t  Q! {$ R: |3 i( K+ @- ^1 N   AssetID:            asset.ID,8 q6 d  R! h  l: P8 l, m; ~
   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount,
5 I# S' v! p( a1 K$ n, |4 P1 E   Script:             script,
& Z/ |1 G$ r  w+ w, e* A1 A   FromAddress:        fromAddress,
6 S2 G  l, L3 D- H! {   ToAddress:          toAddress,
; a/ ?* I( a& i3 P   }0 V2 m  J# K( f  o! v- j" W
创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。
4 Y8 v3 o) v% R+ m5 ~for _, input := range crossChainInputs {- E# w6 R$ [7 K
                if err := m.db.Create(input).Error; err != nil {, l# ^+ a) J- }; ^0 U& G
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))6 l6 a/ g+ K0 o' U
                }
3 _. r9 {4 [. W}
& V3 Z" D/ E1 ^: Q+ O* R# a到这里,对主链到侧链的deposit已经处理完毕。
+ N6 r+ C% p5 k% |(5)跨链交易(侧链到主链的withdraw)交易处理
/ |( m1 F# b- l, H5 z- a9 Q0 C这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。( b* r; r4 i7 ~5 Y. r
3、跨链优缺点
# M- \+ ?; u# L, n2 V# v: j优点
% _8 R$ g* N* F8 Z(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。* E$ P9 X. }7 J* C& T" ^
(2) 可以根据不同需求实现侧链,满足多种场景9 H( Y/ A) j% L: A
缺点" F% n* ^2 N' N0 W6 N: G
(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右# x9 }5 k1 `3 ^  L0 H
(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大; P' ?! _$ e! M+ g
(3) 只支持资产跨链,不支持跨链智能合约调用
1 T+ ?) a$ C: h: S2 W: v" ?# ]% p$ g% u' A4、跨链模型平行对比Cosmos2 M4 Y3 `3 S1 [6 j  L' l8 |3 p" [% Y
可扩展性2 D6 N8 [: d3 A; C& n/ k/ |
bystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。" k2 k, ~" I9 x5 }; ]: \
代码开发进度
5 `) Q0 G' v2 O+ I" avapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。
6 A& b" j  o, ?" L0 a9 o4 R跨链模型
; c! z1 n, w& D7 S% H" a7 \# Vvapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。
" {8 b2 u& X; h: X8 A5、参考建议: D% z# e2 x* {; }, v% I0 ?& P
侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1