Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
213 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。
# j9 c% f+ E3 Y3 `# R& ^0 k+ W* l: Z' ?2 ^/ w- {
Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。3 h8 V8 S& |, j5 ~. o7 r
主侧链协同工作模型! B) u2 b/ N) }4 p

4 h8 N9 t. F' w7 s" |1、技术细节* c. ], u6 B% d( v, }4 f, P
POW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。* a+ W9 i( R6 v+ o4 L5 M2 G; n; V8 V
而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求
) t4 d  s3 k' K! h% q5 v% @(1)跨链模型架构
+ O& \; b. p1 [$ c: H在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。
) c, W0 \! d) i2 \2 ], x(2)节点类型
/ C' b3 b" q& j$ I( c' l跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。
# K4 n: S, a, [/ S( X# G9 J* h(3)跨链交易流程
' E3 k0 I, s2 i/ q, R主链到侧链( M4 B4 I# i" b( m9 o
主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链4 g- p3 Y, l" G$ X1 m+ f
侧链到主链! V3 V+ K3 k# _( V
侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。3 |0 t5 {/ }+ n' M
2、代码解析
& p, O8 `+ N0 q  h跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。1 O( v6 a. e% u. z
(1)keeper启动( \$ H, \' n: q8 r: n3 ], C$ c) @. y
整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。
3 N* w, y7 J4 v$ `8 x, f! i. F& U1 |func (m *mainchainKeeper) Run() {
+ H; o5 v2 B% L        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)8 A8 m# e0 P9 F3 w
        for ; true; 4 D7 Y- R/ w, O
Run函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。
& ]1 b7 }9 u) S6 s(2)主侧链同步区块
6 C0 z- u2 X3 V- X; y* _Run函数会调用syncBlock函数同步区块。
' C+ `3 o( x* Q( U5 e  o5 x, \: ofunc (m *mainchainKeeper) syncBlock() (bool, error) {+ S# I" @/ x7 g% O6 J, k: J
        chain := &orm.Chain{Name: m.chainName}! g6 h5 G4 z6 h, ?) ]2 Z8 I( j
        if err := m.db.Where(chain).First(chain).Error; err != nil {- Z( H4 m- [  o. n" C9 K
                return false, errors.Wrap(err, "query chain")
# \" S9 G4 x& O2 L7 ?        }9 [  f' x2 H% {6 w
        height, err := m.node.GetBlockCount()! r# R( u5 J9 p# r" Y* K
        //..0 T5 l. h8 a/ w; W7 @
        if height
( ?. K/ J" D" \! O5 r' K  s. M这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。$ @' H) a) o1 r( b6 Y# C
height " @$ v) E5 G$ v% ?8 K5 X! I
主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。
, c0 D, `7 C# YnextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1), @( R; O5 G! f

$ `7 m+ o8 O9 @6 c  u这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。5 N% A9 E  D( I) l4 ?
if nextBlock.PreviousBlockHash.String() != chain.BlockHash {0 @& e1 ?# I$ l" a1 d* d# o
    //..8 N4 @3 w6 ]" w+ V7 ?2 Q
}8 T7 F5 e0 f6 Y0 \. Y
在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。
7 y( \* B" [* X9 G(3)区块处理
" q* B: V! q1 t- VprocessBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。# k) _! C0 j: z0 k
func (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {
$ u; Z6 _* \/ r9 V  Z+ N; Z        if err := m.processIssuing(block.Transactions); err != nil {
& S+ S( d* p! K, @. n& j                return err
# j' i2 v9 ~$ h# y) d        }
/ A% y" x$ H3 I, `0 G        for i, tx := range block.Transactions {
& `7 ^$ c: b  z: E: `                if m.isDepositTx(tx) {
+ K# I: {. ~* E6 N, a" u& d, Y' S                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {+ E% q3 q3 r& m( |$ |
                                return err
- f  \: S/ F' O9 |# o                        }
7 t8 ^2 x3 t9 _1 M/ }# m3 N                }( l# ?' X/ s4 y  n0 ^3 v
                if m.isWithdrawalTx(tx) {! n7 s* f4 z; ~% ^
                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {# u( E: S+ _. s0 j% P. y  s* @
                                return err3 h+ h3 V1 z5 O) m- m
                        }
/ r$ d! S  L( V0 c2 [                }' q0 E9 i2 p) t6 c/ @
        }+ e4 t/ I' s% o7 P2 _) x* F
        return m.processChainInfo(chain, block)6 t. M" G* X5 G7 C4 M+ x8 m
}* m, t/ G6 W7 d9 h  A
在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。( d  ?, W7 B1 Q8 ^5 W1 X
m.assetStore.Add(&orm.Asset{- T# |' n: v" I& B4 q7 L
AssetID:           assetID.String(),' K4 M4 ?" Q& o3 p8 i5 w$ X% ?; q
IssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),- t# R$ q5 J( b/ r
VMVersion:         inp.VMVersion,
. O0 |+ N- ]1 G- t6 e- v( yRawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),
) U% u- y' L1 m9 j8 J2 I- Y})/ g% E9 j" W6 g$ _. n
在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。
3 b/ H; v- }. |4 G) Dfunc (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {6 z- [* x# c8 v, s
        for _, output := range tx.Outputs {
8 y, Z, z, j) B                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {
+ x# M( K6 c6 w. [                        return true% Y. d3 f* J: U# W- I# E- a  W$ R
                }
4 @; ~# ^$ d( t' i/ o3 Z: z        }& J( @" V7 b3 N( H( ]
        return false
9 r1 \- `: j1 Q) M6 `  p( l}
; J, P8 I  ^% L5 Efunc (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {7 H+ I0 P7 n0 e; c# H, t
        for _, input := range tx.Inputs {4 R( V. _1 Y, A5 ~% i' O
                if bytes.Equal(input.ControlProgram(), m.fedProg) {
$ D$ b1 E1 Q6 m3 y                        return true. y/ J+ V2 o( D* g/ Y7 y/ ]) B, O/ W
                }
2 a) V. U+ i( k! ?        }
# M" v4 w4 }7 b. W* z4 v8 H        return false
- I5 ?: y! f: u) ^& ^9 Y}
1 P! K3 F$ i, q看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。, `8 f% R& T) F# r; r1 ~: Q
type mainchainKeeper struct {
: y/ g( |1 ?/ g) i' y0 ^        cfg        *config.Chain
9 R' N$ v5 [% o0 @9 f( U- d% G4 H        db         *gorm.DB/ Y$ E! C9 ~) x4 s" S; M
        node       *service.Node% R- f/ Y! v) L' e( E6 z' M- }) B
        chainName  string4 L5 x  E, J9 u0 ]/ N- j2 f* P
        assetStore *database.AssetStore. d) y, O: {. [4 A: g* U
        fedProg    []byte
, T7 K3 G, O( Q, O6 l1 K8 M0 e}
  s- ?: h* c, j(4)跨链交易(主链到侧链的deposit)处理  b- S% ~$ V/ H# Z: {1 j2 Y) X* Z
这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。  a5 Q! |+ e4 p$ `. ?6 ~" x
func (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {
+ z1 e. k# I/ u2 [        //..9 Z$ ^/ Z7 j  ^3 a! @  I/ o
        rawTx, err := tx.MarshalText()1 N& Z' C  m' K! J7 n" w
        if err != nil {$ Z* D! c- J1 U4 s: I, r; S( G
                return err
# F' U3 c% t  O. ?! c        }2 A; B6 v, f, ~+ q2 x
        ormTx := &orm.CrossTransaction{. }, z) f6 I. e- w, _9 M" K
              //..5 F0 T8 j' R4 f: ~
        }
! t$ `' [0 Y. `; u$ e        if err := m.db.Create(ormTx).Error; err != nil {7 j( k, l) a- ?7 S; p0 j; O6 Y" f
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))% z; F+ `  N8 l& a! E4 t# f( _
        }
- ?% m/ V7 p/ G0 W        statusFail := txStatus.VerifyStatus[txIndex].StatusFail3 ^! I; Z* o. U/ h$ q
        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)
8 ?* K: b% K: H/ K        if err != nil {) |& K/ o: l6 B9 q; X8 h
                return err/ n$ t7 ]. ^# O1 E# h$ Y$ ?
        }
* @* T5 p0 B4 |$ ?* [, i8 p        for _, input := range crossChainInputs {  I& m9 s% o- p  S
                if err := m.db.Create(input).Error; err != nil {; i. w. [1 F$ \2 R2 D
                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
$ U7 l, x# J1 H2 g, _                }
' `8 D; m/ k3 }+ x; k  f2 I# S        }
, w( G: u" I* ?2 k2 X0 r4 W. G        return nil6 r( M' ^6 ?1 p# w/ H% e. W
}4 T. ~8 o9 p) t2 h0 D0 J$ e
这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。5 k. A- J3 q& ~  e8 a/ `
ormTx := &orm.CrossTransaction{
/ L3 Z' _3 V6 }" `2 d" R+ J                ChainID:              chain.ID,
7 v& G# r  z6 \                SourceBlockHeight:    block.Height,
2 l: e* H, {( k) }                SourceBlockTimestamp: block.Timestamp,! x$ ~6 Y/ C* P5 _6 Z* C
                SourceBlockHash:      blockHash.String(),0 G1 D0 V' \. j  g: J
                SourceTxIndex:        txIndex,$ j5 ^8 x: [, b& m6 ~# |
                SourceMuxID:          muxID.String(),
" [, p' Q9 l0 E3 t5 {                SourceTxHash:         tx.ID.String(),
% N) e5 V+ J* s9 }  }! B                SourceRawTransaction: string(rawTx),
+ o, ?- m2 b2 t! a2 A! ?1 j7 s                DestBlockHeight:      sql.NullInt64{Valid: false},
* ~% k/ }6 u  u/ M                DestBlockTimestamp:   sql.NullInt64{Valid: false},
+ l. {2 c% d' J1 j; i6 G# c0 H                DestBlockHash:        sql.NullString{Valid: false},# \/ e+ F) t: o) n
                DestTxIndex:          sql.NullInt64{Valid: false},
9 M% m7 [" v( [4 c, C8 q                DestTxHash:           sql.NullString{Valid: false},
# {) ?% @8 F) P' v8 ]2 \. X                Status:               common.CrossTxPendingStatus,, O: i' D* S: X- O9 v
        }
4 ?7 _- u/ F4 Q; K创建这笔跨链交易后,它会将交易存入数据库中。3 W2 l: C/ w, u8 p" x+ U% a+ r
if err := m.db.Create(ormTx).Error; err != nil {
2 n5 ^6 U7 [+ F4 q. S                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))3 r5 w( \' U+ {/ j8 Z2 i, o; [! N
}
$ }# |/ ~( Z6 }3 Z+ J( n! Y在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。: q$ E7 H3 N! Q7 {, |1 ]9 \- `
func (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {4 p3 R- ?( F' O6 i* q8 B
        //../ u3 e' r) [3 R$ f" X' Q5 Z
        switch {2 B1 N# |5 `, T* @4 N" U$ l1 a# H3 _* ]
        case segwit.IsP2WPKHScript(prog):
% y$ [" N- Q- P, y4 H7 _: R+ R7 i                //..' F. W, e: m/ s& O
        case segwit.IsP2WSHScript(prog):  q0 G) {! W4 I. [- `( Z) y
                //..
. S/ V- D0 B! b$ J9 N: [        }
) f) {% G; ^% b$ k; U9 r        reqs := []*orm.CrossTransactionReq{}
9 r4 H. N5 n1 o4 b% X0 q        for i, rawOutput := range tx.Outputs {8 S0 {# g) e& a1 m
                //..& {( e% [0 H7 _0 u4 R& k
                req := &orm.CrossTransactionReq{
! p5 a. W% b9 [- {- v& ^                        //..
& e2 j; B9 f2 }, t                }
, V0 y! l; ?8 b                reqs = append(reqs, req)
# r: u! }& W' H0 }# \        }
7 Q8 }4 Y  _- i5 ]( M% a        return reqs, nil
; d4 `2 |2 g, s1 x, W- e}
5 C$ _1 X+ `- n4 x  C0 B# E( U0 {. f很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。
) f* H" k+ z, L4 jswitch {
- o( h( }/ p* Q# B2 [3 s. }        case segwit.IsP2WPKHScript(prog):8 c1 i2 \+ j4 b( f
                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {) ?8 S$ t: r5 x
                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)* L# B, q: W- l! e) G% M* M
                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams)5 E2 j  V6 E: M) i# @
                }; r9 B( a2 `1 p, @" M. r
        case segwit.IsP2WSHScript(prog):
# ?) _- a  s' ^" l  I$ p$ Y3 H                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {* r4 q" Z% j! M" t& v( i; |3 u
                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)  }% [4 k1 I! ]1 W' ?7 K
                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)' T0 V4 `' U0 q! F2 d: x
                }; R5 O5 f9 e0 f! L
        }
1 K) w( f. l, k0 x8 F: T& h  x在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。) y# }* i) f/ B1 U
req := &orm.CrossTransactionReq{
, J2 `: i4 D* i2 z5 a, z   CrossTransactionID: crossTransactionID,1 Y( ~8 x4 Q0 k' z% e
   SourcePos:          uint64(i),7 a- G0 o9 w4 }
   AssetID:            asset.ID,2 _+ d% S2 l6 P! n5 u; v
   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount,8 w& O% Z) ~9 N7 X9 G
   Script:             script,
) H' _& m  C. a! w0 U3 G. a   FromAddress:        fromAddress,
7 L! Z6 j& t% k1 C. _   ToAddress:          toAddress,: ]& B' a- |9 |& g3 u9 F+ X
   }, K% F5 B. |: H' z. a, N; t
创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。6 G& d, O) y: \& h
for _, input := range crossChainInputs {1 _- y* |5 m& ]2 w. z; l7 V+ G
                if err := m.db.Create(input).Error; err != nil {
  {/ v0 Q& z# h( C6 i                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))* G  j9 r! E" [9 w8 G
                }
3 {3 b: ^; _  }0 F}2 G* C% ~4 G" x3 Y0 Y1 C
到这里,对主链到侧链的deposit已经处理完毕。
/ H& b# |8 l" {# w. T3 G(5)跨链交易(侧链到主链的withdraw)交易处理  `- D6 w9 @9 M) T$ S
这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。& Z, {( T2 C' X) s' w
3、跨链优缺点7 K8 s! ]# e$ z8 E# H$ v
优点! [; J, ~- j; E$ W* h
(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。2 x0 h  z4 u& M
(2) 可以根据不同需求实现侧链,满足多种场景
& m' w9 G2 f! w7 u0 y1 \缺点) a+ w" m( B7 f! K  b2 p& Z
(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右
4 `6 E1 w+ V4 e+ {& o5 [& S4 t) m(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大
( H" P+ R7 i4 }8 S& v  E4 D1 T6 l(3) 只支持资产跨链,不支持跨链智能合约调用& z( \( d9 N& k) C: v
4、跨链模型平行对比Cosmos
7 o# N; E8 R$ _可扩展性4 {. Q+ r  `0 x: C( X& ]
bystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。6 Y" C# }$ @3 B& J  A( J
代码开发进度. @& n- _% ~5 {6 \' c
vapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。
" g6 ~* W$ q- y, y! f! k  {; ^; ?4 k跨链模型) t' y4 `# M0 ~
vapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。
6 m" e$ U- E, h0 P  z5、参考建议# S, k+ c* \+ O' v# T8 l) X7 E: ^
侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1