Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
136 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。
7 I; q! e5 p  r2 j. M0 y* L: a$ @$ f4 n2 u* U
Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。9 U  u5 Z6 E5 s& v+ [
主侧链协同工作模型, h4 Q8 r) @/ Q5 T# g  F
! t. w2 X/ k) t% q1 [/ `0 ^
1、技术细节; o& X( s' n4 I5 m. i0 B; H( z- N
POW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。6 m+ }# `" `3 g4 k! B
而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求
1 R0 A4 G( @) b: i3 Z$ J3 N% `% v(1)跨链模型架构& F& Y1 i4 K# o, O
在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。
. |" E/ f! V* c4 X9 Y(2)节点类型
! d: |6 F+ T  l& j+ @跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。
" C6 o* C2 u. f) n$ h5 t, ^) w2 A& O(3)跨链交易流程
, ^0 B9 o- ]: D! d& x主链到侧链6 L3 _1 H! h% s8 L
主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链
/ P3 q3 j5 B9 _+ v) p% H9 `6 K侧链到主链
. @; [/ p1 n  n2 W4 |5 q侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。
8 ^: c9 X$ d; v; i% }# [# T2、代码解析3 q  Q8 K. |! k$ c5 x
跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。1 W: {% o6 j& S4 h# `9 ?5 |
(1)keeper启动
! s: O) K  \! v# H+ M$ T整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。
/ a8 z; w, m$ e, b$ k5 R$ ^func (m *mainchainKeeper) Run() {
8 p- I+ ?9 I3 c- q5 }        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)
. v8 @6 I% Z& A        for ; true; ) A5 Y9 f* n, Q3 I; E- z5 z. ?0 O
Run函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。
: V) a+ J, u, W2 r& w(2)主侧链同步区块( ~/ l. `' B8 ?# {1 [, x* r% s
Run函数会调用syncBlock函数同步区块。2 T. I; F6 M2 N; G/ T: t$ ^/ h
func (m *mainchainKeeper) syncBlock() (bool, error) {
* z4 J( ^8 x8 n. H# F        chain := &orm.Chain{Name: m.chainName}5 p& b% I; T# A* F, z
        if err := m.db.Where(chain).First(chain).Error; err != nil {( M2 ^. x  F( e" m6 S' i! @
                return false, errors.Wrap(err, "query chain")5 v4 [* @/ G& J7 \/ i3 t2 V
        }1 b, Q, r" g+ N
        height, err := m.node.GetBlockCount()
4 Z4 K& P7 j3 y& W! s' d* o        //..
; `) {4 Q4 `  T; m7 j6 N        if height
% y% C6 n9 J8 M3 i, |6 ?2 q8 j) q这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。2 W( J2 C4 s* e! b
height
+ v1 @* Q" X6 ?主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。8 y$ Q6 c# s0 `# }: [0 S+ P3 _$ J
nextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)4 f; K: @% U7 l! `. V- S

, z9 G0 r+ Z+ A( F6 i+ b7 `+ s6 V这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。0 y% O1 N1 P  j  E) p
if nextBlock.PreviousBlockHash.String() != chain.BlockHash {4 \! a: R1 K" t. ^6 {
    //..9 Y* v( b: _1 K% }) h8 P" d& R' m
}
5 U# E+ j3 b( ~* q/ w在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。# g3 k: [, s- m+ u# E& G
(3)区块处理
6 p, x. J2 w% e( @0 [processBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。$ l! W' g5 n: u. h5 @" m3 V
func (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {
0 r1 }5 A( l7 _  o        if err := m.processIssuing(block.Transactions); err != nil {
* }( r  m2 M" ?  c4 I                return err
, B+ d' L% d1 Y3 q* R$ G# L        }
+ c" N" F3 j( Y, v2 G0 D6 B        for i, tx := range block.Transactions {
- |8 c; o% r/ |4 Y* [! L; }                if m.isDepositTx(tx) {, t* F2 ^! @: C/ I
                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {7 ?+ f3 z! K' |# N2 W
                                return err& _/ a9 f. X: p: B+ A3 k0 [
                        }' ~2 D9 s9 b% o6 ^
                }# y7 B# h) @/ K6 e. [1 d
                if m.isWithdrawalTx(tx) {+ ], \' ?- c1 p4 X3 e4 i( i
                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {
2 o  d5 C, T! Y. b& Y                                return err
- C! s3 u7 q) L- B; Z                        }( l8 a2 }3 p/ |/ H0 ~
                }8 s7 q( P0 C, G' w, r3 {
        }* e/ ^& V+ @2 L
        return m.processChainInfo(chain, block). S# M/ O' L; ?# I- m* `- @
}/ b2 `. O6 J& \& p& }7 f* \, y- J
在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。
! ^' r( U% e" U; h* Y$ sm.assetStore.Add(&orm.Asset{+ G' Q1 W5 i" m- J; \$ |
AssetID:           assetID.String(),
! X2 i# A% R# G  m- n4 Q1 ~  TIssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),
7 v) B$ [  {* ?4 h( \! CVMVersion:         inp.VMVersion,
, H! z4 Q3 ^0 }7 Z5 R. KRawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),
5 o, a% E- M, m6 W})
! `2 Y5 I9 ]1 ~8 B+ k在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。6 x2 f- Q: A# C6 X! h1 x
func (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {  Q* ]0 h4 M, U: k
        for _, output := range tx.Outputs {! x0 m* |9 d3 W" ~% B/ p! L' d, X4 }
                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {, R! f! o- r" i; ]8 }3 N3 o
                        return true
* l1 @! T1 O0 y& T2 T1 n                }
4 p1 U: z. G# [( F% u" j4 K! c        }% v/ E- g8 H) Y9 W3 B; e3 `
        return false
2 Q. h; n# h8 N. `9 `, e1 G  I- g8 {}2 [( T8 U8 U' E$ \7 I! \% h
func (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {
$ v9 Z  X' Z  o! f8 g# d' Q! @        for _, input := range tx.Inputs {
4 i' O* l7 h" I8 s( b- q( u                if bytes.Equal(input.ControlProgram(), m.fedProg) {
$ ~8 h, n1 R; G                        return true
+ _% ~  z- A3 t# X) Z( D0 Z. o                }
9 K" v6 j1 m( Q% q! O  i4 `        }
- Q) {/ G/ p+ k8 ]" |: ~# N9 F        return false
" \& ?9 l, J2 Z* c) H9 Z% t& ^$ D7 O6 G}
3 R- a, Z! A: E* d看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。  `" H7 K3 A' f* d+ h
type mainchainKeeper struct {
9 i2 _9 e; ]7 X" p        cfg        *config.Chain; a! v8 Q) g. W# k8 M" i
        db         *gorm.DB  E3 N' d; Q6 Z, \9 E& A- ^# ~
        node       *service.Node
- [7 Z: o$ K  p% S) X        chainName  string
' z% r* K* ]  R4 ?: a1 E( h        assetStore *database.AssetStore
! U! z7 t. n7 G7 T' x        fedProg    []byte2 F) P( c2 h) i4 X
}; G2 K  O9 x# [6 ?; D. R
(4)跨链交易(主链到侧链的deposit)处理. J" q% ]4 N' t, ^$ J
这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。. Z: z' |( B1 ^/ J. m/ n- w' ~
func (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {* C  J; G3 `6 `
        //..1 H1 L' m4 }5 D0 L# a
        rawTx, err := tx.MarshalText()& Q. y- l( W) F) _* a8 n0 C* v: Z
        if err != nil {
! n% R5 V1 p; B: |: X+ K/ n9 v                return err
- F3 H  p9 h* R. C4 X        }$ f% h) ^  P+ G- b4 T, N3 N' c$ ?
        ormTx := &orm.CrossTransaction{
% K& y1 Z, V! H* x1 r! t3 l# r              //.., ?: {7 a5 Q; f5 T& S
        }
' \2 h: o+ Y3 o, ~* {7 h  H        if err := m.db.Create(ormTx).Error; err != nil {
0 f( Y8 e( L0 b% j3 g3 a: w( T                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
, v8 G! u7 t2 p- u2 @5 `# f        }
! \7 v. b! @4 c# y* r& U! H# v        statusFail := txStatus.VerifyStatus[txIndex].StatusFail
4 Q- ^, d8 \  _' {# p        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)
. c6 R  ]+ ~# D; e        if err != nil {4 y% b( B' E  |0 p  M( e* f& C
                return err
! z% y. Q  C. t  C3 O& B        }
, m5 ]* a& C" p/ l( D        for _, input := range crossChainInputs {& C& f& [6 l/ w6 J6 R: Z' U$ x
                if err := m.db.Create(input).Error; err != nil {
0 Q8 \2 \, k; q' e6 _: M, v                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
& P+ a( H/ ~3 x+ ?$ c/ R9 O4 V( S! [1 {                }4 m* }2 g% i) f' ^6 p
        }& Y  u' T) y1 ]% e0 I8 p* X; x. g
        return nil. J+ p1 ~# T4 _; c
}) T. }. i8 W  A) z. V
这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。7 z  Q4 |$ }7 L
ormTx := &orm.CrossTransaction{
* M" ?- s8 t6 X  G+ C0 E6 m- r                ChainID:              chain.ID,- e0 Y; H' ^/ a4 W
                SourceBlockHeight:    block.Height,2 t) C% E( y  P* w3 h& V
                SourceBlockTimestamp: block.Timestamp,
1 u8 G3 {, D5 }8 l( f/ b                SourceBlockHash:      blockHash.String(),
1 Y# G7 Y7 x% i                SourceTxIndex:        txIndex,: }3 `* Q# q$ _2 d5 x7 p/ U
                SourceMuxID:          muxID.String(),
7 g- @' J  @- `* w                SourceTxHash:         tx.ID.String(),* v7 M9 }# j4 J/ l8 j
                SourceRawTransaction: string(rawTx),% k! _6 R/ U% U- p- Z
                DestBlockHeight:      sql.NullInt64{Valid: false},3 D5 y$ d0 S& A7 K+ T
                DestBlockTimestamp:   sql.NullInt64{Valid: false},2 e  `9 W9 Z7 @! ?+ B
                DestBlockHash:        sql.NullString{Valid: false},
, X  G. J/ ?  m7 X( r* ~, x& A                DestTxIndex:          sql.NullInt64{Valid: false},! U3 ]! e! X. i5 x' t7 ^$ [
                DestTxHash:           sql.NullString{Valid: false},% _/ S7 d0 I. @
                Status:               common.CrossTxPendingStatus,; L6 C( R$ a0 f
        }
4 M. y* s" T0 [, t创建这笔跨链交易后,它会将交易存入数据库中。% G$ {- K  @% P
if err := m.db.Create(ormTx).Error; err != nil {) ~- n4 N) h7 N/ o
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
/ X! U, W2 x  y1 F2 t5 b7 M}
5 E9 n/ P- @4 S在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。
4 j) g" y2 Q. Bfunc (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {& Z6 ^9 m" d0 {9 ~
        //..1 Q+ H' M1 A3 S. {2 J
        switch {
6 g& C8 X/ H- r; y& g/ A        case segwit.IsP2WPKHScript(prog):
% v; g2 ?. \1 @. d/ H' `                //..
  B& u/ k- M' B( X! B6 r3 G# e        case segwit.IsP2WSHScript(prog):
/ e2 U2 {- M. M                //..- W/ o$ z+ o$ t, b% h+ T
        }5 D7 S) V5 q( t6 ]2 H) z+ L
        reqs := []*orm.CrossTransactionReq{}& [# e: p1 t+ Z9 R( t
        for i, rawOutput := range tx.Outputs {
- }! r6 ?  e6 U& Z8 Z+ f                //..: ^; K5 v5 o5 V; D6 r9 A/ I. Y
                req := &orm.CrossTransactionReq{
3 C& v# G+ L" [/ D& j4 e                        //..; ~9 Z, z( Y5 ]1 ^
                }* p- \9 u" y& |* W
                reqs = append(reqs, req)' y$ G5 u4 f1 f1 n7 c
        }. J: j( Y5 X- q, r
        return reqs, nil
' H% K# c# j, _+ Q% r$ u8 A}" k; n, Y2 \3 m0 w* T0 N
很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。* _+ V" y5 M! O& Q- ?/ u
switch {
  a( [+ b5 X" L9 p, u& S' l! x1 t        case segwit.IsP2WPKHScript(prog):
. q; w6 N8 [7 g6 q- |6 V4 v                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {& g3 f3 j: u' b1 x3 Y: H" m
                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)
( E% A6 q' Z7 M, y8 o2 d' n                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams), \; o6 {9 H6 @- _+ w" o
                }  [: Q/ k6 h% V; b
        case segwit.IsP2WSHScript(prog):
$ c1 v6 f  U. v" e. Q. H                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
# _7 }2 K8 A+ ]3 G+ x1 s3 T/ j" e                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)/ ^/ P( x6 ^& p, ]' e2 P! s
                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)1 F. s) q& z. l& p
                }
5 s* r9 W0 Z" @+ f2 a% b        }; H! ]4 ]2 }; T/ x: c/ T* F1 p$ G
在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。3 h1 w/ O: d+ _7 t+ t9 C4 |
req := &orm.CrossTransactionReq{
  y3 S8 m4 B/ {+ ^, A   CrossTransactionID: crossTransactionID,: S0 l) }5 E# E0 i; T, D
   SourcePos:          uint64(i),
6 X* K7 `2 m1 `% x9 w   AssetID:            asset.ID,, S( L  }  u7 h, U9 T
   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount,
0 S% r- S& |" P- d( t  b   Script:             script,$ c; g3 T) G/ w5 k
   FromAddress:        fromAddress,1 j" t' @/ V1 q! d5 n
   ToAddress:          toAddress,+ Z( N# H7 |' s
   }; o. S6 t) {  l/ C
创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。
  S5 c# A4 L$ Y  [6 J& C" Z$ \for _, input := range crossChainInputs {' j; G  m9 N9 M& o: d- _
                if err := m.db.Create(input).Error; err != nil {9 F3 s3 m( s1 c, N9 O; V/ H
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))- {; L% ]( `6 W7 N3 q& I
                }1 `: ^5 ~( C% ?) v
}/ h% K" \  M+ w
到这里,对主链到侧链的deposit已经处理完毕。
5 l6 s* `. X) ^  j8 U(5)跨链交易(侧链到主链的withdraw)交易处理
: `. v1 S3 H( A+ w# k" H! x. e这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。
- p4 U0 Y0 Z- ]9 L" O3、跨链优缺点4 y& `  f# s% i1 \2 }* ?
优点
" X% u, {; i) Y(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。) C* g" z4 Y6 b. Q1 u
(2) 可以根据不同需求实现侧链,满足多种场景( A4 R" d2 @1 p& U/ n; h
缺点% }5 O! `9 Q" |* [
(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右, @( f- @. N' t5 I. B% b
(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大: [( j: z, C* r. R$ k
(3) 只支持资产跨链,不支持跨链智能合约调用
% S: y3 o6 Z  }4 h* J4、跨链模型平行对比Cosmos3 A9 O% Q7 {. ?  O5 _' I$ u4 B
可扩展性
9 j0 ?) h* X5 y: f) T% Q/ b. ~% L0 `bystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。+ Y$ X0 s- Q. K# y; c5 }
代码开发进度
6 L& S1 P3 S1 g) q, ~" B+ }vapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。
4 j* a& B- @! V' @* X跨链模型7 @; U# Y( N  |8 p$ f
vapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。
7 M4 y5 V" Q) N1 P- H4 a4 s5、参考建议2 ?! @5 L2 a' h8 M
侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1