Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
247 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。- c8 T& U. B) l" e7 f
# W) i  H" Y# B& \) h5 ^
Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。
+ s( S+ G8 J, b' [主侧链协同工作模型
# E6 K& n" o# X' W) a
  p. N, w2 S$ }( g4 |- _1、技术细节
% f( v$ I( @  w  L" U" u) fPOW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。- G; g! b, P& X  g- f" P( Q
而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求- g* W1 m5 H3 Q) {! u, G5 l0 W
(1)跨链模型架构. Y6 b' a$ e2 j" Z1 D5 E- o/ P
在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。5 L+ m% Y! {- L8 s7 ~9 E$ f4 \: ~
(2)节点类型6 H2 P0 g9 Y- o: S
跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。
8 N$ [; c& y: y! u4 k0 K4 ?1 f% b(3)跨链交易流程: C4 A# U% D" J4 ~) }$ C
主链到侧链( f6 W4 p+ ?0 u2 ?6 b1 {2 U4 f9 z
主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链! M( L& q, O7 k6 O% N3 j* ~& K
侧链到主链  }7 p6 p) U2 l/ p$ e- P& f
侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。
$ z: G, h" T0 Y2、代码解析
( ^4 k7 J$ X8 v4 H7 j" S) h/ o跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。
% z& r1 i5 {# B1 ?6 D, i* N(1)keeper启动) O: t7 {0 k& T! f. ^1 P
整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。/ O6 z  K) a3 n2 P! |
func (m *mainchainKeeper) Run() {
0 v$ o5 R4 N; l$ j% l  i        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)
) R; Q/ N& r3 x! u7 _9 z        for ; true; . J0 m! U/ n2 T: _& v8 N/ g
Run函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。$ a  }- J+ m4 V, N" f1 w# X, z
(2)主侧链同步区块1 |' B1 f; N$ O+ L
Run函数会调用syncBlock函数同步区块。
) i% s1 s# r9 }9 `func (m *mainchainKeeper) syncBlock() (bool, error) {
8 }+ ?" e7 S+ b& K6 g4 L( g        chain := &orm.Chain{Name: m.chainName}
6 L/ K& B4 O! B* `  s        if err := m.db.Where(chain).First(chain).Error; err != nil {5 f* y' c4 I( @9 Y( ^) }
                return false, errors.Wrap(err, "query chain")
" D) P1 M$ I$ E! T( Q        }" [9 Z; z) R1 s' t
        height, err := m.node.GetBlockCount()' n6 V, @. A* n# u0 m7 v
        //..2 W/ P/ A! Z6 T. \8 U; d6 t
        if height
# ]8 y7 ?4 s2 K6 \* N- U0 N这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。
+ t# E6 p' x! j! }0 H: h8 A* f0 H8 l% n; Xheight
5 n: b. L2 \3 k5 l8 v主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。
' q3 S. {& R0 a0 b+ c& R. ^! SnextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)9 b; c# X6 I) X0 M) s

& k( v2 U+ n& ~6 }/ d这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。
) ]9 b; a' v, T- r! mif nextBlock.PreviousBlockHash.String() != chain.BlockHash {4 ~7 g5 w: q6 g2 F; N
    //... b9 @4 C4 L; C3 D% [
}
+ B7 A( s. W/ f" R; s& m在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。
# P( d, K7 _, G* {2 E(3)区块处理9 v) ~/ v' B" R' J( n7 w: T
processBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。# r3 H  i% p2 ]" z* S
func (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {+ z5 Q* ?9 h5 y9 ^
        if err := m.processIssuing(block.Transactions); err != nil {
1 L5 I7 ^3 k7 P: @. c                return err% x' A" L- u' \" i+ \! K9 g1 i
        }
& F5 z8 v4 _+ u        for i, tx := range block.Transactions {3 x. W; o+ t: U7 W
                if m.isDepositTx(tx) {0 M' Y7 k& |9 V
                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {( k' C! E! U4 L, B
                                return err
# Y, I4 r/ K. w4 L                        }
. ~1 e( X  e9 V( l$ ^' x6 R& l4 o                }
: I- W! H9 _9 _, H/ Q7 E; f4 j0 w                if m.isWithdrawalTx(tx) {. r, x2 n- H) B7 {; ~. \0 m* [
                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {
/ l* I. V& P1 @+ l                                return err
' G, ?2 ?- P4 X; F0 ]) o+ p, Y                        }
+ @( e2 f! {1 G                }
" ?$ c8 h. [; y  ]3 `- S* I        }3 Y( T) B9 k- \
        return m.processChainInfo(chain, block)
( s- Y1 b/ c; i9 u& B0 B}, P7 ]) k+ p4 D
在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。
, i3 B1 T+ i& J3 s9 Z9 l5 c# jm.assetStore.Add(&orm.Asset{8 _. X+ n% ]9 }* |$ z9 ]
AssetID:           assetID.String(),7 }7 F- _2 q: T- P) a+ e+ M4 f
IssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),
2 j3 n! N3 Q5 ~VMVersion:         inp.VMVersion,( o6 N1 G& V9 {- \
RawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),
# i; K( W* \0 x  |})
- w% A. R3 x  q: Z在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。
7 n  {$ N  s  h* ~0 U, t: Ifunc (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {
$ G4 n- L. C- }# w# }: I& [7 C+ D        for _, output := range tx.Outputs {
0 a, ?7 q+ u. u# g8 a6 p2 [                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {
# f0 ]% q& D2 ^* e# f                        return true( t5 \# l8 q# [0 K
                }: b: R/ L" o9 p8 [1 l+ q1 M; {. u
        }& [9 E: d3 j! G( K$ ^* K  Z
        return false# T2 @9 D: S( k: _6 l7 }0 i3 u; z
}; w( [( V; B- X- T; r4 i' z# A
func (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {1 y7 O9 b& r/ r( I5 y; Z# c
        for _, input := range tx.Inputs {4 e9 o8 N; Z2 y
                if bytes.Equal(input.ControlProgram(), m.fedProg) {
# G% E& i5 L1 b8 v7 ?                        return true8 C( s" p0 j  C. E+ T/ x0 c
                }; m* B4 l5 t. k
        }
$ @& ?1 B$ l0 H8 T$ x        return false
1 l. v& ]; `6 }0 F+ O) |9 Y* _3 R& U}
: h! K* |$ C, a$ e) T! s0 o看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。$ d3 a( i1 t! d% r
type mainchainKeeper struct {
9 K7 [/ r# l9 S& V7 r& c        cfg        *config.Chain
+ `1 z" @) D, w8 Z        db         *gorm.DB
1 D4 W2 z; H% D) j        node       *service.Node- S6 ^4 h( D1 y4 ^2 ?! F
        chainName  string
* h7 v/ @0 M4 N/ I8 Z2 f+ `        assetStore *database.AssetStore
6 L! Q7 o! ]6 A( U8 N# f        fedProg    []byte7 q: \; E, D; Z9 k. n4 ]
}; u+ V# X& H0 m# p/ y
(4)跨链交易(主链到侧链的deposit)处理  |7 s% E7 U( b. ~
这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。' U$ R+ J) P& d4 ]
func (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {
; [! O; d- Y: X0 d! R! v        //..
3 f% |# t' v( e0 `7 ~+ _; h+ x        rawTx, err := tx.MarshalText()
) |) m: z$ M# V  O  s# x        if err != nil {
5 [# `; I8 V0 R+ |1 o                return err3 K* D1 W+ z2 L* r1 X2 T) n
        }, \& u1 p3 [2 c- m
        ormTx := &orm.CrossTransaction{
7 Z" Q- a$ z9 @8 L& t, \/ |3 L              //..
: ^& j' A  d: A" q0 U, W: i( e        }
9 P: ^0 }! S1 H* E: `! A        if err := m.db.Create(ormTx).Error; err != nil {
# f( o; g& c) c: E% q+ G, G                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))& X  i8 y% U: H7 `
        }/ j. o: {6 C. `  l8 o. f- @
        statusFail := txStatus.VerifyStatus[txIndex].StatusFail
1 u- ~1 g9 P* O; d7 j& T        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)
% e( w' o+ B1 v. Y        if err != nil {, F* b5 _# s% U& j6 F5 x
                return err# h2 B7 p* s# }3 {
        }
, s& w7 Z, U. S5 W; ^6 S        for _, input := range crossChainInputs {
7 W( [/ \! q( W2 y: P& o                if err := m.db.Create(input).Error; err != nil {
" U, n) r. H3 D$ V                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
# N7 J% m% ~: G4 }8 x; m$ k4 m                }
& s1 q. h, N6 G7 @% A0 i% S        }; a; }  V* S" L0 K
        return nil
  p9 [3 U% L( `5 g# Z}2 x5 i& z7 H- G3 k
这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。. I# ?9 O0 C) H
ormTx := &orm.CrossTransaction{: `( a- q$ `+ p0 t6 V( X9 I6 {
                ChainID:              chain.ID,8 |! R' L* @5 a, E3 p# j
                SourceBlockHeight:    block.Height," q% E/ ?8 d7 J* t8 c
                SourceBlockTimestamp: block.Timestamp,  }. z5 M9 ]8 W/ g
                SourceBlockHash:      blockHash.String(),! [2 I) R$ ]" i; k
                SourceTxIndex:        txIndex,
% {- U' ^7 A3 t4 b/ s                SourceMuxID:          muxID.String(),
* ^1 `$ o. l+ F                SourceTxHash:         tx.ID.String(),* c* X3 X/ o' F2 b0 N9 Q9 g
                SourceRawTransaction: string(rawTx),! X. q' x8 _) L3 z; u! @% b  e; o
                DestBlockHeight:      sql.NullInt64{Valid: false},/ ?. f+ d% c  ~7 R
                DestBlockTimestamp:   sql.NullInt64{Valid: false},* S( O9 v+ ^7 ^3 {9 N8 L
                DestBlockHash:        sql.NullString{Valid: false},
$ e+ \9 E) o. s5 U% `                DestTxIndex:          sql.NullInt64{Valid: false},
# W$ w+ _0 \/ ?9 a" c7 Z+ l! ]7 z1 G                DestTxHash:           sql.NullString{Valid: false},/ D7 G$ b- n4 ^( [! G" B# y
                Status:               common.CrossTxPendingStatus,7 B" Y5 j0 Q  \) Z# ]
        }
! d9 R& u+ [( y6 [: ^( C" R创建这笔跨链交易后,它会将交易存入数据库中。0 |' u+ V& R% s$ {7 m
if err := m.db.Create(ormTx).Error; err != nil {9 X+ z! `6 m1 W2 r6 a
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
7 U; U/ L+ m" B}
2 k4 r; y8 \( ~* O1 }在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。! _1 d* T. \  }
func (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {
. D. d  n: F: P6 P( J3 ]        //..) I" z4 f8 j# I$ P  M( \9 _. ^
        switch {1 s2 m" b3 C- E7 E1 j2 F; w6 T
        case segwit.IsP2WPKHScript(prog):
" W% W5 F' h) v' O. S                //..
9 I, }7 z9 x0 |+ r1 w+ _: Z        case segwit.IsP2WSHScript(prog):
6 a* T  N% @( k- z' i                //..
7 d5 C$ N: E9 B- l        }
/ l" U/ S$ s5 }" r        reqs := []*orm.CrossTransactionReq{}
! B* `' K8 g9 `1 }        for i, rawOutput := range tx.Outputs {
. v- z! d1 {- P7 h4 d, ?; _                //..
3 k. [5 f* @' x% Z" L                req := &orm.CrossTransactionReq{% Q. {6 G/ K: R- D3 W2 x
                        //../ i9 C$ c0 w( ~
                }: t% Q  h0 T& t
                reqs = append(reqs, req)
: i" I5 n& K$ w- A- D6 u. |        }
# Y6 J1 T8 f9 k* o. \- l" W3 \+ ~        return reqs, nil
2 l" ?, Q* w1 h& M  N! L}  ^( v) Y* n( g) w6 {4 p" H
很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。
& k/ P, W. q5 }" X: H! rswitch {! A6 V" J) S0 V6 B8 g: F
        case segwit.IsP2WPKHScript(prog):- _- V3 q6 U  t( @, E' D  ~, v
                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {1 K2 J( y) f2 g* a+ M; {5 i
                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)
. }! I& c' K) X8 \* p) N/ k                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams); X! F9 U/ [9 ?/ Y9 i* L; l2 R
                }& S. o  v+ v$ e* Z5 T
        case segwit.IsP2WSHScript(prog):+ d- Q9 B/ ]1 k- t3 K
                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {4 [( {1 d; c6 E& T% ?1 @/ ^
                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)
" K# a5 d- T: N! n1 b+ z& }                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams)2 N& s( q+ ~& e
                }% n' A$ i; U4 V& o
        }4 C4 t3 M% z( H7 H( R. Y3 ~
在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。
& V! o, c% r* Q( B9 r2 Z6 xreq := &orm.CrossTransactionReq{
4 B; k" l6 z9 R! y. p6 i0 [   CrossTransactionID: crossTransactionID,
! m1 m( @4 Y% |4 V   SourcePos:          uint64(i),3 G6 o5 S4 \( R4 E0 ]
   AssetID:            asset.ID,
) a; o' _0 I. `' x* I$ P# L1 r4 p# W   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount," B7 k; E) E) r5 X. s
   Script:             script,
7 w1 T' b; m. d( {  K0 |   FromAddress:        fromAddress,& o+ l- }: ~# ]% E  Y! u/ C
   ToAddress:          toAddress,8 B8 D+ T/ [' t- w! G* `
   }* u& D! Z& p3 G
创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。' O2 o: z" A9 T5 [" A' E1 Q
for _, input := range crossChainInputs {
* p! |# B  F' ?) Q) h6 [5 R                if err := m.db.Create(input).Error; err != nil {
% s0 [' ]8 p# H1 t  z+ C                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))9 \) o5 Y. C  T( C/ }
                }) N$ y/ m6 ~; s1 M$ @/ X. x+ M
}
" v) B0 r( w$ B/ L( O$ l1 A到这里,对主链到侧链的deposit已经处理完毕。6 l1 T  c, }9 d
(5)跨链交易(侧链到主链的withdraw)交易处理
* O2 C5 w' ~6 X* o/ l6 d7 ?这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。
2 t- p% ]- m# ^6 d% U" q/ A3、跨链优缺点
* M8 {1 F- t! i* k+ |% k优点
0 E  `: \* Y/ |+ k(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。6 X: n, ?0 V6 p9 {, F; E
(2) 可以根据不同需求实现侧链,满足多种场景
. Z$ p! q: f6 r( [缺点6 p$ X; N; b0 U! e6 U* O
(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右
+ b$ L, s- t" A+ u9 V(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大
$ P* L. e! t: t+ }2 ?' l0 ~4 n(3) 只支持资产跨链,不支持跨链智能合约调用
( T9 J- w0 N! c; p* P& G7 x, ~4、跨链模型平行对比Cosmos
; n: q) |6 x2 Q1 `可扩展性( \! k) W7 _; q8 @' G- i) g  k
bystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。0 o6 p$ j6 F( [& `
代码开发进度
* \' J; `8 I/ `* \0 ~. V- |% _& yvapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。
$ {* q& _" W- O% C+ j( R* m# \跨链模型- {  z1 _5 E; h/ [. T5 K
vapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。* ]4 J, m+ v3 \5 b  j8 ~/ H( O
5、参考建议$ `9 e, S3 @+ ~
侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1