Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
246 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。- N8 p6 n3 w1 X3 `
7 @; @% q; w  t4 x1 Q
Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。
: y/ G  x; L* j0 ]2 f主侧链协同工作模型
* _& v7 Q4 Z/ F1 L; X7 t4 W. s7 X! z. K( ?' P: `1 |
1、技术细节
+ y$ F) g5 N# RPOW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。3 {$ y  y4 y( {3 s- I) ]
而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求
% G6 A1 E. Z( l5 z0 W(1)跨链模型架构, i2 {% o3 D* O1 _8 x  m
在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。
4 y$ p" C9 U+ N" Z) Z% N(2)节点类型$ s8 R9 B+ x8 a. f
跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。3 |/ U' z6 Y0 k1 H: M( N1 p9 o3 O
(3)跨链交易流程1 T$ c+ b7 ?* p. E; A9 [$ W5 @6 I4 u
主链到侧链
' m/ z$ p! B6 S& X主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链6 X' [& r4 g, H0 w% ]0 g$ J
侧链到主链( a0 o9 c7 p4 \7 j. h3 r
侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。
% u  o, _5 i2 g! c; G2、代码解析
! A6 L1 @! S" k- v/ w跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。- X! Q6 }6 t# ?% f7 s
(1)keeper启动
1 {3 |0 n; k. Z9 @, M' H$ ?整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。
& U( f7 n4 _2 R/ b3 W4 w  Afunc (m *mainchainKeeper) Run() {0 P* U+ @7 s; \
        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)$ z8 h1 u3 J& d# X0 T" q9 ?
        for ; true; 2 B: K2 J! c/ N: L; |; f/ i
Run函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。5 I7 X/ E$ D- G6 w8 A5 A3 S
(2)主侧链同步区块
  g8 ?8 K. t5 G+ S) e% c" M$ RRun函数会调用syncBlock函数同步区块。
9 N: ~+ t! N3 {0 N4 xfunc (m *mainchainKeeper) syncBlock() (bool, error) {& s* b" V, R. F1 R4 v4 j4 Q
        chain := &orm.Chain{Name: m.chainName}$ V: p6 C7 V1 n5 |6 U1 B# N5 W
        if err := m.db.Where(chain).First(chain).Error; err != nil {. W# h: a: x. {* f
                return false, errors.Wrap(err, "query chain")% v$ V, l0 {5 ]( O9 w& P, M
        }
# R. T6 w0 G; U3 y# w5 o2 o/ R        height, err := m.node.GetBlockCount()
  V* K' x! |' X6 {        //..# @  A' g: }- F# E
        if height
& [- Q9 l- v) U0 z0 D* s0 u这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。
8 K1 c, |: @; z' k! Zheight
% y* S7 m% u+ C# b9 C0 P主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。: N  _8 a1 [* J; G* t3 n, ~
nextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)
! T2 Y0 Z- f; ~9 `' I6 a
& f' e" ?$ V$ z" W+ n' @4 a这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。
% n) ?9 v% ]; l! yif nextBlock.PreviousBlockHash.String() != chain.BlockHash {- C- v# }" }8 L  p5 ]. i* E
    //..( E- X+ ?0 O5 O' W% d9 n
}
8 }1 ^- u# l# E+ j- o* t7 J在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。
6 _# b$ m$ ^+ |% }8 ^7 e" X(3)区块处理6 _4 E! h! K( m% R6 `
processBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。
/ v' T. T. \9 K, ^! h" U4 L8 n" Jfunc (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {; x& o0 x6 k6 f+ Y
        if err := m.processIssuing(block.Transactions); err != nil {7 Z- G: i: ]6 H& D  [
                return err' Q* T& ^6 \/ `! q' t" P
        }
% ^0 ]1 N& R: ]4 `* p& d        for i, tx := range block.Transactions {% W1 P4 I4 W, V' S2 F- q# f
                if m.isDepositTx(tx) {" @" q1 W- j: i; ~+ W5 }
                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {, s8 u) P# [; U) }: g
                                return err; E" S6 N7 r2 J8 I/ W5 D
                        }: O3 c6 y5 ?, R0 I! W
                }* }! o" a# k7 `) x
                if m.isWithdrawalTx(tx) {' W. a+ x* I2 `
                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {
% I5 P4 z8 |, ~" m                                return err
9 |8 j+ n) F  T+ d" g' M5 y( `" T                        }" R! _! J6 c( o
                }
" O. T) ]) i1 r) A/ ], F& C        }
/ x8 V# Q. i$ j* j" o2 J0 c' [1 ?; q        return m.processChainInfo(chain, block); Z0 ^, p: d5 a6 L! g
}1 D, v, K/ g& [$ Z2 h) _! O7 }
在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。+ P; F. z% B5 d
m.assetStore.Add(&orm.Asset{
8 h' A" v0 s6 ?2 eAssetID:           assetID.String(),
/ ~; a! r$ i; o3 Q$ @IssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),
/ D; e& G2 _$ n) o4 HVMVersion:         inp.VMVersion,( [8 ^" q: z6 f8 V) j+ C
RawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),
0 }3 ~: k0 W6 D8 u})
8 a( y6 b/ N$ h% u在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。
- y& ~7 u  G0 E" yfunc (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {
  a; ^* r  b) q. x        for _, output := range tx.Outputs {
' R+ E" S* w) \! D0 ~                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {3 a. _: M% w- {& L( r* u, h
                        return true# z! q( x9 E! o/ C6 I/ `
                }! g" ^. v: K8 x6 r6 J+ K" \
        }
5 i5 R9 p% R) ]1 i. |        return false9 O9 T" j% X4 ^: Q, ^8 P0 N# \
}
  `, S' Q; P! l# M7 ]  q2 Jfunc (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {7 C* N( L! j$ |; ~9 t% @* Q: g! g
        for _, input := range tx.Inputs {+ W0 g6 [  ?& X2 [8 T8 D' i( M
                if bytes.Equal(input.ControlProgram(), m.fedProg) {
. ]6 A  _8 l- o' H( X                        return true
% Y$ s% _( J/ C1 L1 K! @$ s                }) u' L; q4 N2 \; z
        }% H. O5 \3 I; G5 _% N; j8 P
        return false
, |# L4 G. S7 g/ ]$ q}  u! |3 j5 C- J' q
看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。
8 d. Y$ K$ M, Q! d" Ftype mainchainKeeper struct {
4 \( Q; E) {$ u, P+ R        cfg        *config.Chain  e* y+ s$ F, Q* D+ V" S. \
        db         *gorm.DB
2 [5 m- P! J' H( g1 A2 [, b        node       *service.Node
( R8 q. m" z  R% m        chainName  string: }0 ~) w& _- E% f9 @# I
        assetStore *database.AssetStore# P# a  G1 @' r$ R
        fedProg    []byte8 D1 h( t: Q7 A- g) H
}  k3 k6 {+ [+ C) e: i. r
(4)跨链交易(主链到侧链的deposit)处理
. y: H8 h4 u. b1 C3 L$ s! Q  Z" d9 X. \这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。
3 M8 j# [: ^' L; \! Gfunc (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {( ^+ h7 x$ x$ M: \* _+ M8 f. P' p
        //..5 r7 ^! J9 _, }% Y# e1 f6 M
        rawTx, err := tx.MarshalText()" E; l( I. o5 p" n2 P0 U
        if err != nil {  C. |( H! O; X4 Q2 z3 `
                return err
8 [+ `7 \8 z* t. g- Q- Z' K        }
8 Q) O6 z6 J/ u        ormTx := &orm.CrossTransaction{0 B8 m# d2 U/ K
              //..
# ^7 B- x- X- M: ^9 K6 M5 q        }' b: R+ q/ V1 ?( F: O
        if err := m.db.Create(ormTx).Error; err != nil {: n- ^4 q( W( y1 Y. l
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
4 M: ~. {7 h6 ?( Z: n& l        }5 u6 ]& u0 P7 O3 C7 z) o
        statusFail := txStatus.VerifyStatus[txIndex].StatusFail3 }3 L7 H+ P. ~+ v9 m9 ]. x
        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)
9 \$ g# v4 z- Y8 ?        if err != nil {0 l6 Y' f5 C* v* M
                return err" S  m1 B0 K. T: l. U- e
        }; v) t  S+ S4 h# M4 g
        for _, input := range crossChainInputs {" V2 q. V' l' C' N$ v) N$ n. v
                if err := m.db.Create(input).Error; err != nil {% q: u' l- f7 c7 Y! e5 }$ g
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))7 P6 Y( O- v% J( u
                }1 i0 U) H8 R2 t! q# n
        }9 y7 K& o: J' k# @
        return nil+ ]+ k% t# F- E
}
- S4 o/ d' ^" T! h: D- k& ?3 U- `这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。* [: G. U7 a- u; A: n9 J& S
ormTx := &orm.CrossTransaction{
' E6 w2 a* t8 r                ChainID:              chain.ID,
3 Z2 X4 X# }: @2 X7 j1 L5 k7 h                SourceBlockHeight:    block.Height,
( Z  I2 h' O. ~  u                SourceBlockTimestamp: block.Timestamp,. r5 `! K# e1 B) H& h; \, w
                SourceBlockHash:      blockHash.String(),
3 K! B- P6 I/ }! ~2 T                SourceTxIndex:        txIndex,
2 ^1 p! t+ \- A$ r                SourceMuxID:          muxID.String(),
, }4 I* r/ h/ R3 |" f  z                SourceTxHash:         tx.ID.String(),7 t, l( Y% D2 r- D# ~
                SourceRawTransaction: string(rawTx),$ k# e8 g. O8 ?! N( b
                DestBlockHeight:      sql.NullInt64{Valid: false},
8 {4 P$ Z4 }# K9 x, C                DestBlockTimestamp:   sql.NullInt64{Valid: false},& z. o4 I' o& A. A
                DestBlockHash:        sql.NullString{Valid: false},7 E" ]2 o! q+ V; ~7 P0 }1 Z
                DestTxIndex:          sql.NullInt64{Valid: false},
' H# M/ |6 N& n2 q                DestTxHash:           sql.NullString{Valid: false},
; X. I7 H+ Y! W2 i: Y# A0 W/ @$ A                Status:               common.CrossTxPendingStatus,
# L6 U/ S' X/ H1 q8 |6 ]2 \7 b        }
* O$ o& u+ S5 P! O; R1 K: O创建这笔跨链交易后,它会将交易存入数据库中。
; @7 E' M5 k- @" V+ `1 ]if err := m.db.Create(ormTx).Error; err != nil {
: [$ C  N# x3 e8 o" X- F                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))" {* B( r. W) q. @
}) v# Q( m% A$ p; `1 U
在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。" N6 {6 x' F$ f, Z5 e
func (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {/ A. w# j8 w1 h9 r* V$ J# K9 t
        //..
$ P) }! w  z9 N, x- _& F        switch {# t8 F* N/ V- f6 r, c
        case segwit.IsP2WPKHScript(prog):( u2 z, F# c/ Z6 ]3 d% k4 J# I
                //..* ]' M6 x2 y9 V2 E6 o: z3 e! B
        case segwit.IsP2WSHScript(prog):
# Y0 X3 f) \. h" S/ o5 S                //..5 S; z* P5 t' S/ i1 m8 J# |
        }6 {- @* @9 `: X: K
        reqs := []*orm.CrossTransactionReq{}
- r# b) `& [4 i        for i, rawOutput := range tx.Outputs {
& L- q/ u$ D, v  ~5 n                //..* K: _1 U7 a& k4 u1 z# n" j0 e4 R' `
                req := &orm.CrossTransactionReq{
2 v$ z. l, c& T  _2 i. l                        //.." [7 q- U6 n% J$ o0 r7 B. I7 Y
                }
% B) |4 ?: {! @+ X                reqs = append(reqs, req)/ S& N; K, p# H  y8 A! K
        }7 ?* Y! i* N: p5 e
        return reqs, nil
# z; U/ ~- w5 N- p% n/ |7 `7 L% ?7 u  k}
5 Y2 O. a6 U1 Z6 T8 j/ ~% G: t很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。6 ~; s6 c& \6 f! t3 v
switch {# Y, I+ {  t5 O: U
        case segwit.IsP2WPKHScript(prog):  J/ |* m1 L/ z' T0 T
                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {8 _1 U; A- r4 x/ ]! R. s$ P+ S
                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)6 P/ z3 J5 T: {0 I$ a
                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams)  H" q* |" |) H% c2 p9 e) o
                }
! g1 Z: \3 t0 D$ _/ M; |1 {        case segwit.IsP2WSHScript(prog):2 @  T+ Z& y  A& _& `- L
                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
6 g7 L: V* }8 ?+ e* l% H' \0 Y% [                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)3 x2 j0 }  X0 i& m8 i
                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)
; y* Y2 L& R& f, \                }
; G9 \  m! L) L" p+ P        }
3 d1 k: C1 [, e; D在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。# `  R; y: `$ a) v! S
req := &orm.CrossTransactionReq{
# ?( z$ Z# a* R0 A) E   CrossTransactionID: crossTransactionID,7 N/ Z3 n- r- s% e, h. i
   SourcePos:          uint64(i),7 U' r! ^/ d8 M; G$ A& |+ T9 e- Q
   AssetID:            asset.ID,2 ?5 \: g& t/ n! y
   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount," @! K3 j4 a+ }4 }- v  o
   Script:             script,
% f! f7 Y6 t' ^# M# C8 Z" z; L   FromAddress:        fromAddress,9 \  q; e, S# C" ~- j* @
   ToAddress:          toAddress,4 q3 y" [. J. Q7 r" W5 Y" |
   }1 x$ W/ {$ @2 h- f
创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。
3 R0 s; u& g8 u/ \$ |$ D" ?for _, input := range crossChainInputs {/ p) j8 H5 @8 R, Q3 F  Q0 N, Y' ]
                if err := m.db.Create(input).Error; err != nil {
8 }8 D0 l* ^1 Y) c" a/ G3 Y7 v                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
) L* w8 e! l/ n6 H                }
+ M- W2 o6 L* r0 L/ Y}1 s" S5 @0 ~+ x9 i
到这里,对主链到侧链的deposit已经处理完毕。
; |9 H$ m4 K2 [# I: u3 u8 ~(5)跨链交易(侧链到主链的withdraw)交易处理' p+ ]4 v6 ^) @2 }% A
这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。( D9 L& z" j: U. ^: s$ R
3、跨链优缺点
6 [/ Y' B; a( Y) J3 x* r6 [优点2 X' p. H9 Z, F8 O
(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。. o) q2 ^' {7 X' d% @
(2) 可以根据不同需求实现侧链,满足多种场景
, D1 x. ?' k* k0 V$ _% w缺点( D2 Z" L5 P' u* ^
(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右5 E6 w0 |/ H( S
(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大
2 L$ z3 Z" Z4 O(3) 只支持资产跨链,不支持跨链智能合约调用! @- Z  u! G: a& i2 E( f
4、跨链模型平行对比Cosmos! d% e; r$ ~* s& {, ^8 Q0 G
可扩展性
& S9 x5 r" F+ u; qbystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。: w0 X/ S+ |( \3 }+ }* D! c9 K
代码开发进度6 ?1 q5 E) s/ x8 z' w& I- v) b3 i
vapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。
  c- x0 {6 m! [跨链模型% ]: y! f) _0 Y1 J% S4 v8 n
vapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。0 t) l& h+ c3 L9 S, C. E
5、参考建议* c7 J& j5 P4 a2 v4 K( l4 ^6 Q! G
侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1