Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

Bystack跨链技术源码揭秘

123458243
214 0 0
Bystack是由比原链团队提出的一主多侧链架构的BaaS平台。其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层。底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公链。侧链扩展层为Layer2,为多侧链层,vapor侧链即处于Layer2。
) i9 I3 q, B. |
" a3 s! I/ B" |Vapor侧链采用DPOS和BBFT共识,TPS可以达到数万。此处就分析一下连接Bytom主链和Vapor侧链的跨链模型。& z1 g# _+ c7 u1 Z
主侧链协同工作模型3 J7 n$ F- F7 [
. B- A6 D7 B0 _5 ?8 K
1、技术细节: z  Q: K+ W4 ]! }8 t7 I. A
POW当前因为能源浪费而饱受诟病,而且POW本身在提高TPS的过程中遇到诸多问题,理论上可以把块变大,可以往块里面塞更多的交易。TPS是每秒出块数*块里面的交易数。但是也存在问题:小节点吃不消存储这么大的容量的内容,会慢慢变成中心化的模式,因为只有大财团和大机构才有财力去组建机房设备,成为能出块的节点。同时传输也存在问题,网络带宽是有限的,块的大小与网络传输的边际是有关的,不可能无限的去增加块的大小,网络边际上的人拿不到新块的信息,也会降低去中心化的程度,这就是为什么POW不能在提高可靠性的情况下,提高TPS的原因。
" `% j; N9 d! O: B6 m8 `而BFT虽然去中心化较弱,但其效率和吞吐量高,也不需要大量的共识计算,非常环保节能,很符合Bystack侧链高TPS的性能需求
8 |2 }. A5 b- g(1)跨链模型架构
+ V9 j! T( W; \6 ~) N. ~0 R在Bystack的主侧链协同工作模型中,包括有主链、侧链和Federation。主链为bytom,采用基于对AI 计算友好型PoW(工作量证明)算法,主要负责价值锚定,价值传输和可信存证。侧链为Vapor,采用DPOS+BBFT共识,高TPS满足垂直领域业务。主链和侧链之间的资产流通主要依靠Federation。5 W* y# X' t8 d. \4 b+ }
(2)节点类型
0 J% }+ C) J7 U0 {2 N跨链模型中的节点主要有收集人、验证人和联邦成员。收集人监控联邦地址,收集交易后生成Claim交易进行跨链。验证人则是侧链的出块人。联邦成员由侧链的用户投票通过选举产生,负责生成新的联邦合约地址。
$ o+ `- }& m* M$ i( i6 Q% `(3)跨链交易流程5 H- U- E; u7 u! p( ]) m1 t# o
主链到侧链  w. P% t: T& J7 W: ?% F/ p
主链用户将代币发送至联邦合约地址,收集人监控联邦地址,发现跨链交易后生成Claim交易,发送至侧链0 r) A3 q+ H2 A
侧链到主链
9 A' _/ `6 S1 Q! h' ], _, c9 s侧链用户发起提现交易,销毁侧链资产。收集人监控侧链至主链交易,向主链地址发送对应数量资产。最后联邦在侧链生成一笔完成提现的操作交易。2 y! q* V, Y+ @, z$ U! `& F
2、代码解析
6 X# A9 g6 c% o2 e4 \  F1 `: j  [# O跨链代码主要处于federation文件夹下,这里就这部分代码进行一个介绍。
3 y: b% c8 S3 u% Q5 t(1)keeper启动; S8 _9 U; U5 \# w5 G) w% F; f
整个跨链的关键在于同步主链和侧链的区块,并处理区块中的跨链交易。这部份代码主要在mainchain_keerper.go和sidechain_keerper.go两部分中,分别对应处理主链和侧链的区块。keeper在Run函数中启动。% o  t1 H4 t* R, ~+ i
func (m *mainchainKeeper) Run() {
8 W  k. @& B: h8 }5 G8 C4 u        ticker := time.NewTicker(time.Duration(m.cfg.SyncSeconds) * time.Second)
( e7 O9 ^  e1 f1 z        for ; true;
, V. @! B! ~( w% _Run函数中首先生成一个定时的Ticker,规定每隔SyncSeconds秒同步一次区块,处理区块中的交易。4 ?+ o0 ]2 [1 q, {% x
(2)主侧链同步区块
  S1 R1 Y2 A. B) KRun函数会调用syncBlock函数同步区块。
2 D2 e: C& e$ t* o1 r( ufunc (m *mainchainKeeper) syncBlock() (bool, error) {
$ ^) X* x: ~( N5 i) V+ w2 {8 X9 z        chain := &orm.Chain{Name: m.chainName}" {2 I2 I2 p2 z0 }2 Z' g
        if err := m.db.Where(chain).First(chain).Error; err != nil {* E! f7 s/ F/ M2 o- r( U* S, f/ p
                return false, errors.Wrap(err, "query chain")0 }1 ~8 {. d  U3 q* D1 E+ X( r) g
        }
/ I. ~  s) s* \' [' }. D- D9 G6 F        height, err := m.node.GetBlockCount()
1 o0 t# t: B9 y# F8 B  z* ]! O        //..! O( w, B! ]' r1 C1 _* C, l) ]7 T
        if height
2 R: W3 Y* D2 F这个函数受限会根据chainName从数据库中取出对应的chain。然后利用GetBlockCount函数获得chain的高度。然后进行一个伪确定性的检测。
6 J1 k1 h' h, S5 ^& }- s8 Uheight
! I/ u1 [* }' g/ ~主要是为了判断链上的资产是否已经不可逆。这里Confirmations的值被设为10。如果不进行这个等待不可逆的过程,很可能主链资产跨链后,主链的最长链改变,导致这笔交易没有在主链被打包,而侧链却增加了相应的资产。在此之后,通过GetBlockByHeight函数获得chain的下一个区块。
/ F5 W% I) q& B7 EnextBlockStr, txStatus, err := m.node.GetBlockByHeight(chain.BlockHeight + 1)
! _7 y1 B' r5 E" P( p5 \4 b4 T1 J$ x1 ?$ |9 f) g' H- K
这里必须满足下个区块的上一个区块哈希等于当前chain中的这个头部区块哈希。这也符合区块链的定义。& Q5 q* {& Y9 ~0 S+ d5 G; n/ _
if nextBlock.PreviousBlockHash.String() != chain.BlockHash {
& t7 y4 X" v5 q* c% n4 N    //..
" B& d  J- U/ e) z# J}
- T! B- K( O# @7 I在此之后,通过调用tryAttachBlock函数进一步调用processBlock函数处理区块。
. ^* }" P' G5 @( a(3)区块处理* o9 w6 |9 W6 S4 W+ @4 D4 ]1 Z8 L
processBlock函数会判断区块中交易是否为跨链的deposit或者是withdraw,并分别调用对应的函数去进行处理。
& S8 g; \6 }0 B2 z1 k9 afunc (m *mainchainKeeper) processBlock(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus) error {, M  c! j; ?( F
        if err := m.processIssuing(block.Transactions); err != nil {
+ ~, q: g) p$ ?% K' `$ ?                return err" J3 s+ E$ b  ~" d
        }' t3 D$ d* c! g( ]+ g# y: i6 @1 i
        for i, tx := range block.Transactions {, t1 d0 u* ?6 C
                if m.isDepositTx(tx) {6 \: {9 g( K, ?7 l- b$ Q2 j+ Q
                        if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {& V8 V3 V0 I9 r% ^+ s6 n
                                return err- s% s, n9 v! n( Q6 H' g7 B
                        }
$ }6 u6 h9 h, g! z/ ]' O5 H                }9 ^8 ]7 Y3 E& p9 Y0 _
                if m.isWithdrawalTx(tx) {
# n1 }3 s# m& _; w                        if err := m.processWithdrawalTx(chain, block, uint64(i), tx); err != nil {- p, h6 q& c8 Z; Z2 @
                                return err
8 {) z4 ^8 B! x                        }  D/ C3 W5 q4 e9 P, x
                }
! _& i4 G+ e; y3 O- p1 C2 B! m6 H        }
+ m+ t& C( ]: M, I        return m.processChainInfo(chain, block)
$ i1 L3 c* {. }0 |, B& U/ Z; I6 ?}
* ~" z. ~! y1 g在这的processIssuing函数,它内部会遍历所有交易输入Input的资产类型,也就是AssetID。当这个AssetID不存在的时候,则会去在系统中创建一个对应的资产类型。每个Asset对应的数据结构如下所示。
) E% w6 \8 ~  P7 Q1 z; o0 X+ Dm.assetStore.Add(&orm.Asset{
: k8 M) l, \$ l( Q2 c; ~9 }( ]AssetID:           assetID.String(),
/ h7 @1 `, q; S4 Q0 I! `IssuanceProgram:   hex.EncodeToString(inp.IssuanceProgram),+ D! r5 T8 ?- E! @  F  u1 O
VMVersion:         inp.VMVersion,
0 v+ ?# x: B- i3 @" A9 \5 M) }" r( vRawDefinitionByte: hex.EncodeToString(inp.AssetDefinition),
$ q. B* k9 V0 k$ n4 o) r})( N  ^. u: Z+ h: o
在processBlock函数中,还会判断区块中每笔交易是否为跨链交易。主要通过isDepositTx和isWithdrawalTx函数进行判断。8 D2 Q4 {4 H# R
func (m *mainchainKeeper) isDepositTx(tx *types.Tx) bool {
1 A" s4 ^. Y, f$ z; p3 Z        for _, output := range tx.Outputs {
. m( |0 A7 G  I" ^! _+ N                if bytes.Equal(output.OutputCommitment.ControlProgram, m.fedProg) {& \/ _. M$ R% V! X/ R
                        return true
: a0 h* ]; w+ F2 K  [; X                }
2 r7 x) M3 A3 N; _        }" b8 ?" D0 K$ Z; W7 r
        return false
8 D  X* A$ }1 J6 b}
! B' Y3 O( R% g! R; S2 T; R+ X* Mfunc (m *mainchainKeeper) isWithdrawalTx(tx *types.Tx) bool {
0 L+ g, ?3 D5 r        for _, input := range tx.Inputs {
$ o$ O, b6 n5 k& k                if bytes.Equal(input.ControlProgram(), m.fedProg) {1 O, I8 q7 r( T4 A; \# o! H( s
                        return true
% G8 c) x% q5 q4 i                }2 a6 C& m# [. r+ t
        }
/ w& Y4 T' \% b* n7 F        return false5 W1 X4 f' Q8 [; f: w
}
3 t" D- T# M2 T看一下这两个函数,主要还是通过比较交易中的control program这个标识和mainchainKeeper这个结构体中的fedProg进行比较,如果相同则为跨链交易。fedProg在结构体中为一个字节数组。
4 S4 C3 l+ i' [8 N$ L- Stype mainchainKeeper struct {
4 t  r6 n$ Q  E+ i8 ?* ~+ h        cfg        *config.Chain0 ]; }. R5 f) m: I
        db         *gorm.DB. M  i3 j& j3 q" f) s. a/ a4 v2 C
        node       *service.Node
' a9 B1 @2 g5 y6 D4 G        chainName  string
7 _1 p/ F) q6 @9 U        assetStore *database.AssetStore
7 t- k9 \( g1 I0 h        fedProg    []byte
2 t7 o- \% P2 x' n& Y}
# I1 U1 K9 W7 h3 R(4)跨链交易(主链到侧链的deposit)处理: P! J6 G, y+ ]5 v: W8 U* ?
这部分主要分为主链到侧链的deposit和侧链到主链的withdraw。先看比较复杂的主链到侧链的deposit这部分代码的处理。! m  _% v/ k$ i  j5 w
func (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *types.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *types.Tx) error {
3 n6 E7 D+ U: h* m8 U; P: n- [7 x        //..
8 z. D( L5 T/ l" U, e        rawTx, err := tx.MarshalText()
: b+ H$ Z8 w5 h4 Z. p" C7 H        if err != nil {
" W# w* m8 [1 a                return err6 |! z' C# @! P$ [
        }1 K, j. J8 [9 Q2 o& N' V0 g+ _
        ormTx := &orm.CrossTransaction{: o7 d1 S7 t& a6 V; i
              //..
  B- l9 _  l5 J' ~4 ?        }
$ l' u* H& {) [6 z" a+ O$ Z3 _, ~        if err := m.db.Create(ormTx).Error; err != nil {
' a- y, I$ G4 T                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String())); T% r1 D4 o& C# h/ Z2 A
        }
5 B6 E% Q- r$ Z        statusFail := txStatus.VerifyStatus[txIndex].StatusFail
2 @9 }8 a$ l( T- Q# X9 [        crossChainInputs, err := m.getCrossChainReqs(ormTx.ID, tx, statusFail)
4 q3 P4 ^9 _! [* K, ^        if err != nil {
; E5 k0 a& U9 w6 Y4 K3 V$ E3 U                return err
, T3 `  C4 S* |$ J8 S) }        }
  u( x4 a) E" A; v2 g0 ]! O        for _, input := range crossChainInputs {
$ N  E( @1 r. a& t" i$ J! G                if err := m.db.Create(input).Error; err != nil {
- W5 w: {" l4 P; v                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))0 M- }" f6 R! {$ Z  m
                }
" g! L$ d/ m1 j2 j# z+ a! i        }
+ h! s, E9 R1 ~( R' }- e: @8 F: _        return nil
& I& j5 }' L$ p0 y}
8 ~4 |" I7 J4 z3 M' K; g9 f6 H这里它创建了一个跨链交易orm。具体的结构如下。可以看到,这里它的结构体中包括有source和dest的字段。; T5 Z- C1 x8 s3 |& n% P2 s
ormTx := &orm.CrossTransaction{0 |2 |. \/ d0 [4 C. v$ f
                ChainID:              chain.ID,
' Y0 e8 K3 X7 }5 X. s3 s8 |                SourceBlockHeight:    block.Height,+ N0 \! c* D( a
                SourceBlockTimestamp: block.Timestamp,
  b! Q* n4 Y5 G  ^1 J" V                SourceBlockHash:      blockHash.String(),
: y0 p1 F, D0 _5 ~) ~( e                SourceTxIndex:        txIndex,  Y* f- a" K! d$ r' \% D* p
                SourceMuxID:          muxID.String()," W4 G$ M+ d3 \
                SourceTxHash:         tx.ID.String(),
9 g( }& d& G$ O& V                SourceRawTransaction: string(rawTx),
7 G2 k- s% d* l. X0 C* L                DestBlockHeight:      sql.NullInt64{Valid: false},
0 c9 B- o4 @' L8 z1 }/ m                DestBlockTimestamp:   sql.NullInt64{Valid: false},+ a4 A8 B3 K# }
                DestBlockHash:        sql.NullString{Valid: false},! J/ g& I" c2 y4 _# P6 D
                DestTxIndex:          sql.NullInt64{Valid: false},5 W% M% H3 K1 f/ Y4 S: G2 P
                DestTxHash:           sql.NullString{Valid: false},
& a6 s' p! W: {; M% r3 Y                Status:               common.CrossTxPendingStatus,
9 \; Z. ?. D  h# y  c& @: ^$ f, I        }
2 ~+ L3 K; S* r/ l创建这笔跨链交易后,它会将交易存入数据库中。
  z1 U$ h4 M7 s. f' m5 {if err := m.db.Create(ormTx).Error; err != nil {; C! y$ {" L  D3 \5 K! o5 B
                return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
) |" W1 D" Z/ S% r* b7 Y, m& U6 {}
0 X( W. o# N1 |6 d在此之后,这里会调用getCrossChainReqs。这个函数内部较为复杂,主要作用就是遍历交易的输出,返回一个跨链交易的请求数组。具体看下这个函数。6 _: a! c* h0 e  z# P. U0 W( g
func (m *mainchainKeeper) getCrossChainReqs(crossTransactionID uint64, tx *types.Tx, statusFail bool) ([]*orm.CrossTransactionReq, error) {- g6 t8 T$ D7 W# I: F$ `
        //..
& p' J# o) a4 |. |" T        switch {! D# S7 L2 a7 b7 q6 q& I. M
        case segwit.IsP2WPKHScript(prog):( t* J- k3 g  g" W$ F: i
                //..
9 f% b' p' e- ~6 k        case segwit.IsP2WSHScript(prog):
* G2 ?" _+ [% }; T* k) |                //..
" Y+ \& @9 G& @# ~; p% b0 H5 P5 p        }
& n' x- i" F: \; z; @, R% r3 r        reqs := []*orm.CrossTransactionReq{}5 w4 f: X" t& A) q1 y0 g! J
        for i, rawOutput := range tx.Outputs {3 b% k% I8 N& p/ r, k0 V
                //..) z  F7 X+ C  L! e( N, [
                req := &orm.CrossTransactionReq{( k& m" H: U3 R9 ~' e- F
                        //.., j- ~1 d6 v" W
                }$ Z; i: q( ^: n, ]- w2 u
                reqs = append(reqs, req)4 u+ q& Y* |( _8 Y. {
        }9 T9 T! \$ _" j* T: W, A
        return reqs, nil( n2 a7 D% s# R- ?/ [, I
}- h. p: S: G" a! d3 ]
很显然,这个地方的交易类型有pay to public key hash 和 pay to script hash这两种。这里会根据不同的交易类型进行一个地址的获取。
$ ^, j5 x+ w3 w# f6 k0 w7 Yswitch {
# ?/ Q) y% l' b- X( Q        case segwit.IsP2WPKHScript(prog):; o0 j1 g# G3 H" ?2 Y
                if pubHash, err := segwit.GetHashFromStandardProg(prog); err == nil {
: q' P  |8 B' C1 y6 O                        fromAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.MainNetParams)" I2 E1 }( w+ k0 K
                        toAddress = wallet.BuildP2PKHAddress(pubHash, &vaporConsensus.VaporNetParams)
9 Y$ |5 W6 `6 Y9 |) S8 m* i                }
6 w' [4 w4 M. |, [( j( z        case segwit.IsP2WSHScript(prog):' _8 _7 [+ Q5 Z& s3 v' ?' X
                if scriptHash, err := segwit.GetHashFromStandardProg(prog); err == nil {' R2 n) e' ]; M+ a& Y! f: E$ Q" ^
                        fromAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.MainNetParams)+ I+ _, y+ W1 Z- A, d# {. L# d; v
                        toAddress = wallet.BuildP2SHAddress(scriptHash, &vaporConsensus.VaporNetParams): x8 y9 }% `8 Q8 x+ a: p
                }
2 f4 K7 o# k/ z) P9 s        }
$ F/ T# E; T7 i+ t$ c; K在此之后,函数会遍历所有交易的输出,然后创建跨链交易请求,具体的结构如下。
8 j8 X  K. p" X4 Q/ D! }req := &orm.CrossTransactionReq{( E) {" n' k9 X3 x/ g4 r4 G, J# \4 M
   CrossTransactionID: crossTransactionID,6 X3 U3 `6 t. n" L3 U! a
   SourcePos:          uint64(i),
  v) b- Y) W! E/ M* i( J( g   AssetID:            asset.ID,
8 @, ?$ d0 a1 C* F$ t: _/ I   AssetAmount:        rawOutput.OutputCommitment.AssetAmount.Amount,
3 p+ n7 N2 I  L0 q* L   Script:             script,8 ~; O- x$ C" \
   FromAddress:        fromAddress,
0 u! v& U) F; z  \7 Z, N, X- C& A   ToAddress:          toAddress,& e5 }  b2 u& A* Y
   }( J" a* R9 s1 x" t0 o
创建完所有的跨链交易请求后,返回到processDepositTx中一个crossChainInputs数组中,并存入db。3 f: K* v. j" Y* w
for _, input := range crossChainInputs {
9 K# s. x" m9 \                if err := m.db.Create(input).Error; err != nil {
4 T- [) l5 |1 K& y                        return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
5 c9 p4 c5 P) O/ A# ~                }
: B) H1 Q  z' y6 ?0 e) Z! k/ L+ X}
) m; d+ W! s. u: [: p% y2 Z$ t到这里,对主链到侧链的deposit已经处理完毕。
- m- B) U  C5 }* M3 B. i6 w6 r(5)跨链交易(侧链到主链的withdraw)交易处理) s7 b2 M$ b% U" h. Q" p
这部分比较复杂的逻辑主要在sidechain_keeper.go中的processWithdrawalTx函数中。这部分逻辑和上面主链到侧链的deposit逻辑类似。同样是创建了orm.crossTransaction结构体,唯一的改变就是交易的souce和dest相反。这里就不作具体描述了。
7 H- G8 W4 O: L* A8 M1 h1 w3、跨链优缺点( v+ f1 b3 V0 v! z7 n* q0 m0 v3 s
优点) B& Z: H, P9 |- s* W6 ~8 a4 p
(1) 跨链模型、代码较为完整。当前有很多项目使用跨链技术,但是真正实现跨链的寥寥无几。
8 P- @% J2 N' C7 d1 M4 n- X(2) 可以根据不同需求实现侧链,满足多种场景
* n9 q. u) p7 c2 N: J缺点
9 B) n! d7 q. F8 b" [8 Q(1) 跨链速度较慢,需等待10个区块确认,这在目前Bytom网络上所需时间为30分钟左右
$ W" k5 n% M5 l- j/ b(2) 相较于comos、polkadot等项目,开发者要开发侧链接入主网成本较大
! q, H( q0 l3 P! B! t# k- l. ~& T- M(3) 只支持资产跨链,不支持跨链智能合约调用
2 D1 M" B: C8 J5 h% s" Q$ ^4、跨链模型平行对比Cosmos, e3 Y! P& k8 W& k4 A
可扩展性2 O9 q9 P7 L' {; |5 Q, K/ J0 S
bystack的主测链协同工作模型依靠Federation,未形成通用协议。其他开发者想要接入其跨链网络难度较大。Cosmos采用ibc协议,可扩展性较强。
' v" e2 }& Q4 U- X/ q& E代码开发进度
2 V6 [! S1 y' W) X' Y' i0 Jvapor侧链已经能够实现跨链。Cosmos目前暂无成熟跨链项目出现,ibc协议处于最终开发阶段。
0 b2 h) G9 y' X跨链模型9 L& g, Z9 s( p
vapor为主侧链模型,Cosmos为Hub-Zone的中继链模型。4 w3 j  m/ e8 d/ Y. C: G' C+ A( [
5、参考建议% d0 Z+ z( X% R. X
侧链使用bbft共识,非POW的情况下,无需等待10个交易确认,增快跨链速度。
标签: Bystack 跨链
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

123458243 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1