Bytom交易说明(账户管理模式)
V刘晨曦
发表于 2022-11-13 23:52:49
164
0
0
Github地址:https://github.com/Bytom/bytom
Gitee地址:https://gitee.com/BytomBlockchain/bytom" g9 I5 [/ ^$ F/ i6 M B: N' R
该部分主要针对用户使用bytom自带的账户模式发送交易
1、构建交易
API接口 build-transaction,代码api/transact.go#L1204 `- c! a/ T) Q- H* L6 |$ f
以标准的非BTM资产转账交易为例,资产ID为全F表示BTM资产,在该示例中BTM资产仅作为手续费,该交易表示花费99个特定的资产到指定地址中。其中构建交易的输入请求json格式如下:; \& k, \3 O" w1 M/ }2 m
{7 K: F1 a0 S& ^6 O$ I n% i' Z
"base_transaction": null,
"actions": [1 f* e% m/ u* a1 ]9 P6 f8 F
{
"account_id": "0ER7MEFGG0A02",9 c7 Z0 T( L0 u; g& n
"amount": 20000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"type": "spend_account", Y3 c# S* h# L% h
},7 }- j( a: A& O& V. m
{& X8 g/ V- I7 O4 [; S F+ J
"account_id": "0ER7MEFGG0A02",9 @# a# r, V- F7 H" u7 o
"amount": 99,
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f",* {) [& N4 \0 y3 w" `
"type": "spend_account"/ e# \" f6 z! S; U) N! L! H
},
{7 F9 L1 ?2 V% Z+ z% b- u
"amount": 99,
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f",: u% }9 ?4 R, X, {* h& {
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",. A6 z& M2 M- S. q$ v% P
"type": "control_address"3 \% s- E$ i0 a \/ o( ?+ q; O1 m
}! O2 f# t6 s* D
],
"ttl": 0,, |; G$ @ c% M' |# F# T
"time_range": 09 E: y1 ^3 L/ n# Z! w
}
对应源代码的请求对象如下:
// BuildRequest is main struct when building transactions
type BuildRequest struct {
Tx *types.TxData `json:"base_transaction"`
Actions []map[string]interface{} `json:"actions"`' l- s! G* O" c. z) g5 B
TTL json.Duration `json:"ttl"`
TimeRange uint64 `json:"time_range"`
}
结构字段说明如下:
Tx 交易的TxData部分,该字段为预留字段,为空即可; B" G3 t) N8 H! i3 ~
TTL 构建交易的生存时间(单位为毫秒),意味着在该时间范围内,已经缓存的utxo不能用于再一次build交易,除非剩余的utxo足以构建一笔新的交易,否则会报错。当ttl为0时会被默认设置为600s,即5分钟
TimeRange 时间戳,意味着该交易将在该时间戳(区块高度)之后不会被提交上链,为了防止交易在网络中传输延迟而等待太久时间,如果交易没有在特定的时间范围内被打包,该交易便会自动失效
Actions 交易的actions结构,所有的交易都是由action构成的,map类型的interface{}保证了action类型的可扩展性。其中action中必须包含type字段,用于区分不同的action类型,action主要包含input和output两种类型,其详细介绍如下:6 Z' ]3 W5 K. A% O( V" C& i% h
input action 类型:
issue 发行资产, j: w% G! J9 q3 a! m6 s9 A0 I* c
spend_account 以账户的模式花费utxo
spend_account_unspent_output 直接花费指定的utxo
output action 类型:
control_address 接收方式为地址模式7 n9 [5 N8 b0 Q2 f
control_program 接收方式为(program)合约模式
retire 销毁资产4 X" n' b# b9 i3 z' x* G% `
注意事项:
一个交易必须至少包含一个input和output(coinbase交易除外,因为coinbase交易是由系统产生,故不在此加以描述),否则交易将会报错。
除了BTM资产(所有交易都是以BTM资产作为手续费)之外,其他资产在构建input和output时,所有输入和输出的资产总和必须相等,否则交易会报出输入输出不平衡的错误信息。
交易的手续费: 所有inputs的BTM资产数量 - 所有outputs的BTM资产数量9 O m. R0 Q6 t% N4 `/ S
交易中的资产amount都是neu为单位的,BTM的单位换算如下:1 BTM = 1000 mBTM = 100000000 neu& M. i* T: P8 S' z6 F- ~; |, f- _
) k3 E3 H8 U, C5 E5 S
action简介& D) y/ R6 C w" o
下面对构建交易时用到的各种action类型进行详细说明: O( T! _1 z! D
issue' z4 D# N9 ~9 E' [0 y& J) k6 j
issueAction结构体源代码如下:
type issueAction struct {
assets *Registry
bc.AssetAmount- k5 A+ m/ O8 S) f3 t" p% o
}
type AssetAmount struct {; s9 C+ d3 O2 k4 S
AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"`
Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"`) e- ?6 \1 u6 | J/ A
}
结构字段说明如下:
assets 主要用于资产的管理,无需用户设置参数
AssetAmount 表示用户需要发行的资产ID和对应的资产数目,这里的AssetID需要通过create-asset创建,并且这里不能使用BTM的资产ID
issueAction的json格式为:
{
"amount": 100000000,4 h4 ~& y# z. Q: W; V! ?
"asset_id": "3152a15da72be51b330e1c0f8e1c0db669269809da4f16443ff266e07cc43680",# r# ~8 X' w9 ^$ S$ T
"type": "issue"1 S* W5 Z3 W3 b4 g2 s; ]. Q
}
例如发行一笔资产的交易示例如下:
(该交易表示发行数量为900000000个assetID的42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f的资产到接收地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费为20000000neu的BTM资产)
{
"base_transaction": null,5 {* ?8 j4 w% z1 n
"actions": [5 N. M( l9 I4 S
{' B" Q3 e9 i& I: J
"account_id": "0ER7MEFGG0A02",1 {; B4 |% L. \2 J6 a* I& ?
"amount": 20000000,% V8 b- s9 X: f
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",8 h/ V4 z: H n
"type": "spend_account"% ?8 P) D- y, W/ c7 T- Z
},
{
"amount": 900000000,
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f",0 l1 t# i9 l% w1 i6 }7 ] U& `% J
"type": "issue" F$ |5 |1 c. e3 L
},
{
"amount": 900000000,
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f",* U2 u3 V! @+ s+ T
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",2 s# M5 N: N; B
"type": "control_address"
}
],
"ttl": 0,
"time_range": 0
}( p) `6 ~% s6 z5 d, e- }0 |8 C
5 ~5 S1 H" K! j6 Q0 r
spend_account) V9 S; H& p, H4 H" w1 O& `
spendAction结构体源代码如下:$ G Z7 A+ B! |6 P7 u
type spendAction struct {* m# Z" V( u+ M+ t8 H7 A7 y
accounts *Manager
bc.AssetAmount% I! R4 [8 e2 Z# N3 b( Q
AccountID string `json:"account_id"`, _" A& ~/ e4 S7 t% Y
ClientToken *string `json:"client_token"`! z8 a# \# V. ]1 n: c+ V0 `% G. ]
} V; U7 M3 Y& J+ j6 U% T3 N
type AssetAmount struct {
AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"`
Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"`$ E% n c! y* w7 X, L& ]
}; {0 N8 `! c3 j: U5 B+ k3 F
结构字段说明如下:
accounts 主要用于账户的管理,无需用户设置参数
AccountID 表示需要花费资产的账户ID" z- f& C4 ?! L* _4 D8 A8 Y
AssetAmount 表示花费的资产ID和对应的资产数目
ClientToken 表示Reserve用户UTXO的限制条件,目前不填或为空即可
) L' W$ W* p/ g5 e& c
spendAction的json格式为:( w; C: Q- a( y- V- C0 I# s3 y
{
"account_id": "0BF63M2U00A04",8 R9 k5 H9 q4 p5 V) z
"amount": 2000000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",: u3 ?2 t7 d# `. F
"type": "spend_account"' _4 f: T. O. W
} g/ a& y7 H/ |8 ?- B
例如转账一笔资产的交易示例如下:* @! [0 M5 Z* {* c1 f) W% N
(该交易表示通过账户的方式转账100000000neu的BTM资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费20000000neu = 输入BTM资产数量 - 输出BTM资产数量)4 t% S* h: B0 I4 [; Q {
{3 p+ a, P, U$ x- F/ }" t1 j- q
"base_transaction": null,
"actions": [6 q0 `5 w% {( ^+ Q B; a
{
"account_id": "0ER7MEFGG0A02",; x8 c& ~) S+ w! L
"amount": 120000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",$ E5 F" B6 {3 a4 K" A9 t" Z) n5 T, q
"type": "spend_account"5 o& X, B5 f" E
},. L1 V' U, d. U8 @8 ]" N
{
"amount": 100000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",
"type": "control_address"* E+ h9 C y o6 o# w# p9 `
}
],+ r+ R: z" @1 d9 s. p
"ttl": 0," C- U4 V6 m o( P# f: C
"time_range": 0
}5 a5 }: N- R$ d7 S! O
( y0 a& A. q S5 @6 K* J
spend_account_unspent_output7 ?) d$ l* J& f/ w6 x: W- U
spendUTXOAction结构体源代码如下:1 K: u! g& K. R7 r* K
type spendUTXOAction struct {
accounts *Manager+ h y, L8 e2 L6 C* [
OutputID *bc.Hash `json:"output_id"`
ClientToken *string `json:"client_token"`9 G% j3 u2 g6 y& |4 V; H/ s! T/ n% d
}
结构字段说明如下:6 w/ x3 `" q. y7 i! ?
accounts 主要用于账户的管理,无需用户设置参数
OutputID 表示需要花费的UTXO的ID,可以根据list-unspent-outputs查询可用的UTXO,其中OutputID对应该API返回结果的id字段
ClientToken 表示Reserve用户UTXO的限制条件,目前不填或为空即可3 h" m0 p1 ]' K
8 m$ I' h4 ~2 _8 }. |
spendUTXOAction的json格式为:
{/ \3 T2 Q' C, g' K
"type": "spend_account_unspent_output",
"output_id": "58f29f0f85f7bd2a91088bcbe536dee41cd0642dfb1480d3a88589bdbfd642d9", V' b) w7 h+ v5 n
}
例如通过花费UTXO的方式转账一笔资产的交易示例如下:- f( |# f( \* U
(该交易表示通过直接花费UTXO的方式转账100000000neu的BTM资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费 = 输入BTM资产的UTXO值 - 输出BTM资产数量): `+ j1 F8 Y- ]# U0 m0 J+ C9 {
{+ d N4 S$ d* a( ^" X/ D, Z" o
"base_transaction": null,5 D5 O: y+ A8 f( _( ~1 x) `
"actions": [, ]$ ]' I) J, ^$ i/ a9 G
{
"output_id": "58f29f0f85f7bd2a91088bcbe536dee41cd0642dfb1480d3a88589bdbfd642d9", \3 S7 B, `6 y" F
"type": "spend_account_unspent_output"
},
{
"amount": 100000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",6 R0 m [) H4 z6 }
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",4 J( d5 f0 n7 L4 r/ j5 Z: f
"type": "control_address"
}# g! _2 X0 W" @+ M- j9 k
]," q8 B; h, d6 g! u4 |* u1 i* I
"ttl": 0,
"time_range": 0
}) m& m$ e/ X( j( @$ s" M
control_address" O d% i K$ Q# [# ~; a0 `3 L1 L0 c
controlAddressAction结构体源代码如下:
type controlAddressAction struct {- c# B3 E+ b! {: b7 e
bc.AssetAmount7 [0 o: m2 @' w; `; ]% y4 ~0 J0 r/ ]
Address string `json:"address"`
}, H8 E" }9 W4 e$ J k
type AssetAmount struct {
AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"`3 ~4 }, H& b B
Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"`' Y! s5 q8 G( a7 o) _7 k7 F( Y% u
}% |+ s$ D$ [1 w S0 d8 p
结构字段说明如下:, M K+ k$ q: P- V
Address 表示接收资产的地址,可以根据 create-account-receiver API接口创建地址+ d& B* t; t3 ^+ D4 ?+ a M" g) U
AssetAmount 表示接收的资产ID和对应的资产数目
controlAddressAction的json格式为:
{4 r% ?; Q/ f! R. R R- S
"amount": 100000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"address": "bm1q50u3z8empm5ke0g3ngl2t3sqtr6sd7cepd3z68",
"type": "control_address"
}
例如转账一笔资产的交易示例如下:
(该交易表示通过账户的方式转账100000000neu的BTM资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中control_address类型表示以地址作为接收方式)
{
"base_transaction": null,) s; j6 T- m" Z8 O$ ~
"actions": [; n5 D; p1 O/ e |' N) D3 R
{2 O5 ~, i% h- H& \8 O9 |
"account_id": "0ER7MEFGG0A02",
"amount": 120000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",; N6 [+ I& D; M A0 a# g
"type": "spend_account") e3 A3 E1 `4 Z. N9 M$ b+ W- Z/ V
},
{. H& V. R* _3 p% d7 n( L& i0 [! o
"amount": 100000000,6 f) l5 V7 t! [. m+ e U
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",1 g2 x+ E7 o( ]; `9 y7 M
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",! t% M* y( U. b+ m8 a5 l9 J: n
"type": "control_address"9 f R0 q9 ~# L, f c! b: F8 ^
}
],
"ttl": 0,+ f6 X% q: u1 D
"time_range": 0, r8 {' \/ U% {: ]
}
7 Q( _% A& }. l
control_program
controlProgramAction结构体源代码如下:1 Y& q( B7 A; @/ K) Y. ^/ ^
type controlProgramAction struct {
bc.AssetAmount
Program json.HexBytes `json:"control_program"`
}0 |. S; }1 r" L
type AssetAmount struct {
AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"`
Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"`0 L$ @9 | C5 q
}
结构字段说明如下:$ ^9 U# J4 E9 n7 x) v9 C8 @
Program 表示接收资产的合约脚本,可以根据 create-account-receiver API接口创建接收program(返回结果的 program 和 address 是一一对应的)( _7 h, t' ?% O% O8 p
AssetAmount 表示接收的资产ID和对应的资产数目$ B0 x! `: @. l9 O7 j9 s
controlProgramAction的json格式为:4 k+ j0 s. h; u+ ~' Z! l
{
"amount": 100000000,2 Z Q6 U4 V# ?1 Y9 _3 v
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"control_program":"0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19",
"type": "control_program"
}# B! ?; N/ \# o+ V) ^1 N
例如转账一笔资产的交易示例如下:8 }' z9 U+ c* n/ X }; U+ s: m
(该交易表示通过账户的方式转账100000000neu的BTM资产到接收program(跟address是一一对应的)0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19中, 其中control_program类型表示以program作为接收方式)+ r" B- q/ j0 n( @" B* ]) e l
{
"base_transaction": null,
"actions": [; t8 g1 H; U2 D
{6 m% {' a* @" ]
"account_id": "0ER7MEFGG0A02",9 t. d1 m8 @/ {0 i9 o* g5 x! |
"amount": 120000000,# A# }7 E/ w- B* C% m, _
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",7 m0 ]& A" S3 n5 W5 K% R# T
"type": "spend_account"
},5 h7 X& O0 i% \: \, z) `
{+ U) L3 l$ L# e! G& }
"amount": 100000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"," o* r1 M: ^( F( @, ]/ a/ q
"control_program": "0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19",
"type": "control_program" e; E, o# p, c5 N; h5 d5 P+ [7 h2 B5 t
}1 J; v0 O; }& C
],; f7 |4 C6 K% j3 z; s8 A, l
"ttl": 0,
"time_range": 0, @* y1 [3 Q$ D% K1 m+ X: H) f
}, d; y' L8 i, {/ o( c8 {
# k4 A& n9 U4 w X" h o
retire
retireAction结构体源代码如下:$ n/ i' V0 n# J/ m
type retireAction struct {/ h( c. N* s. T. Y5 c
bc.AssetAmount* P' E8 V# \8 [, m1 w6 U2 y
}; d- g! @4 ~$ B2 W: M
type AssetAmount struct {% }* K& w3 _2 X _9 T
AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"`
Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"`2 H' S' ?6 ^. R
}
结构字段说明如下:4 o# a. U- o) @. P: `; l" |2 e
AssetAmount 表示销毁的资产ID和对应的资产数目
retireAction的json格式为:9 M9 A7 H `( t) e& q1 l2 T) F5 I
{& Y3 `6 w: r, ~: q7 g: D
"amount": 900000000,) z5 e, L" Z0 s7 S9 c9 v) D' g. m
"asset_id": "3152a15da72be51b330e1c0f8e1c0db669269809da4f16443ff266e07cc43680",# W0 Z8 D. W) g5 `+ v
"type": "retire"
}
例如销毁一笔资产的交易示例如下:0 W' X6 q. U) ?9 Z7 }2 B: Y
(该交易表示通过账户的方式将100000000neu的BTM资产销毁, retire表示销毁指定数量的资产) d6 v |( x7 b
{
"base_transaction": null,
"actions": [
{# _' f& n j+ Y
"account_id": "0ER7MEFGG0A02",; r% z* C# ?( {* [' K- u0 ?8 A; {
"amount": 120000000,/ L7 g) x" @# B
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",# C$ K. Q3 q6 z3 ?8 p" @
"type": "spend_account"1 p! O# O" E! K; c2 q
},
{
"amount": 100000000,, g7 p# ` a: Z2 X6 a3 ]5 C+ R4 U
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",8 ~/ |. n" w+ M9 b# ]- e
"type": "retire"7 R8 T! q2 l. N C7 s
}
],5 s& K4 S1 i" F2 ]& \
"ttl": 0,
"time_range": 0
}% l7 g& H' J2 H$ A
build-transaction的输入构造完成之后,便可以通过http的调用方式进行发送交易,构建交易请求成功之后返回的json结果如下:
{- L0 D& h, Z& c6 }2 K2 J( @) u3 T' _
"allow_additional_actions": false,8 _+ {9 P' v7 U5 c. I) C- L$ g
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a077301000161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf456010003013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100",+ @7 ^- P, B: a) U, @4 M
"signing_instructions": [
{4 T7 X" ]& _! }- g1 H
"position": 0,8 \* K6 a. s. R5 _# k
"witness_components": [4 T% |9 h3 f; M; X2 a) j
{% x$ K! F7 }6 Y( o2 e
"keys": [
{
"derivation_path": [
"010100000000000000",3 D5 ]5 L3 }+ h# \6 v. h$ [6 Q
"0100000000000000"6 ~& A/ {( h0 [- i
], }3 ?& v) j- X; r9 i
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}
],! M7 }; D d$ L8 r8 h$ I
"quorum": 1,
"signatures": null,
"type": "raw_tx_signature" w9 O9 D( a% {$ c* }# R
},- [- D9 m; j" L7 {: P- F
{) p( K# V( P1 H) b
"type": "data",1 |9 k& @0 |9 v
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"5 c' U8 Z+ O9 X9 \/ `
}( T$ }6 F, o/ g2 ~
]- M3 H( v7 q0 ^) ?8 ^* C
},# Q& S8 }' h- \; v4 h$ E; b
{& Q: N9 B; X: H2 g6 v, ~8 V
"position": 1,' G6 x$ J9 _* v ~/ g# |8 A9 z$ G S
"witness_components": [
{; P; p: W2 Q0 L- o, _
"keys": [- { M0 T; Z& |1 Y& C; s
{
"derivation_path": [
"010100000000000000",
"0800000000000000"0 K6 v- O( {$ _ r( V& M
],
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}, U, p) k4 x& q3 v
],# W. `2 ?4 [% R2 e# {. c
"quorum": 1,! r8 i' L3 H) z- I i
"signatures": null,
"type": "raw_tx_signature"
},
{
"type": "data",9 A6 T8 n+ a+ Y9 [8 R! Y
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419"
}1 D9 }; g% v7 A- Z* M( {" E
]) T' n/ B& y+ w5 J3 m; g4 T
}
]
}/ H; y( B D j" d2 T4 Q0 X' i
对应响应对象的源代码如下:
// Template represents a partially- or fully-signed transaction.
type Template struct {( ?8 Z: b! s# Y; w
Transaction *types.Tx `json:"raw_transaction"`
SigningInstructions []*SigningInstruction `json:"signing_instructions"`0 q* Y: S' H& N% S+ X* y6 e' l
// AllowAdditional affects whether Sign commits to the tx sighash or
// to individual details of the tx so far. When true, signatures
// commit to tx details, and new details may be added but existing- s W. q8 u1 h9 R2 E
// ones cannot be changed. When false, signatures commit to the tx
// as a whole, and any change to the tx invalidates the signature.
AllowAdditional bool `json:"allow_additional_actions"`
}
结构字段说明如下:
Transaction 交易相关信息,该字段包含TxData和bc.Tx两个部分:; u( \/ m% ]# ?$ @7 B* U1 T% Y3 m; M
TxData 表示给用户展示的交易数据部分,该部分对用户可见
Version 交易版本 W/ A( p5 C1 p4 m7 O8 k
SerializedSize 交易序列化之后的size% O' q4 M6 } J! a
TimeRange 交易提交上链的最大时间戳(区块高度)(主链区块高度到达该时间戳(区块高度)之后,如果交易没有被提交上链,该交易便会失效)
Inputs 交易输入
Outputs 交易输出
bc.Tx 表示系统中处理交易用到的转换结构,该部分对用户不可见,故不做详细描述
SigningInstructions 交易的签名信息) _8 B' G$ M& y1 f/ _
Position 对input action签名的位置
WitnessComponents 对input action签名需要的数据信息,其中build交易的signatures为null,表示没有签名; 如果交易签名成功,则该字段会存在签名信息。该字段是一个interface接口,主要包含3种不同的类型:
SignatureWitness 对交易模板Template中交易input action位置的合约program进行哈希,然后对hash值进行签名4 N& n: y$ s2 a7 \5 O/ E5 [
signatures (数组类型)交易的签名,sign-transaction执行完成之后才会有值存在
keys (数组类型)包含主公钥xpub和派生路径derivation_path,通过它们可以在签名阶段找到对应的派生私钥child_xprv,然后使用派生私钥进行签名: k* J; Y( O, ^3 Y d: q) S3 f& g
quorum 账户key 的个数,必须和上面的keys的长度相等。如果quorum 等于1,则表示单签账户,否则为多签账户
program 签名的数据部分,program的hash值作为签名数据。如果program为空,则会根据当前交易ID和对应action位置的InputID两部分生成一个hash,然后把它们作为指令数据自动构造一个program$ U/ @4 ]% K; i
RawTxSigWitness 对交易模板Template的交易ID和对应input action位置的InputID(该字段位于bc.Tx中)进行哈希,然后对hash值进行签名+ [$ B* [/ _) M4 j
signatures (数组类型)交易的签名,sign-transaction执行完成之后才会有值存在0 g6 b, X- `) C* O m
keys (数组类型)包含主公钥xpub和派生路径derivation_path,通过它们可以在签名阶段找到对应的派生私钥child_xprv,然后使用派生私钥进行签名
quorum 账户key的个数,必须和上面的keys 的长度相等。如果quorum 等于1,则表示单签账户,否则为多签账户5 f1 P4 n4 z* a6 ~" c
DataWitness 该类型无需签名,验证合约program的附加数据
' n7 x5 i( A: K0 {
AllowAdditional 是否允许交易的附加数据,如果为true,则交易的附加数据会添加到交易中,但是不会影响交易的执行的program脚本,对签名结果不会造成影响; 如果为false,则整个交易作为一个整体进行签名,任何数据的改变将影响整个交易的签名/ \: O/ A, `. Y( l
估算手续费
估算手续费接口estimate-transaction-gas是对build-transaction的结果进行手续费的预估,估算的结果需要重新加到build-transaction的结果中,然后对交易进行签名和提交。其主要流程如下:: S1 C. K6 g! Y6 m% j
build - estimate - build - sign - submit5 v) b- j5 x' S9 B& k O1 V$ Y
估算手续费的输入请求json格式如下:
{5 Q& @3 a. W1 ? q0 d2 Y1 B' e
"transaction_template": {
"allow_additional_actions": false,
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a077301000161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf456010003013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100",
"signing_instructions": [7 C; w) q6 C/ U- g$ m7 g
{
"position": 0,4 p! [& ]: m. c
"witness_components": [0 `( o' ^) e6 V/ c' m
{: u* a7 ~1 A' I) x$ d$ G
"keys": [" h! L2 J! N+ Z( p @3 I
{$ A, J) O a) Z* J; A* ~- v4 a
"derivation_path": [- y! {. ]$ ?" U1 I# c
"010100000000000000",
"0100000000000000"
],7 d/ }' d) `. ~5 W3 S; k
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}
],( N8 {* u V( r% d( x
"quorum": 1,) G5 c$ K9 i7 C: a. k
"signatures": null,
"type": "raw_tx_signature"/ J: ?. e# O8 y n- a/ g% Q
},
{
"type": "data",7 s3 ^ M7 |0 U t+ s
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"
}
]7 ]' {3 |& q" F3 b
},
{
"position": 1,
"witness_components": [; ]4 A: M; S; K6 R- X% M( z; ~
{
"keys": [ y3 f' Q1 q) U. t$ f
{% p; ?: E3 e4 [
"derivation_path": [2 s' c1 } c5 r5 }2 h
"010100000000000000",
"0800000000000000"+ t3 h/ ^5 ^# y# B0 M9 C
],
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"0 g! z2 G+ U f
}6 P( \# x$ G$ O0 D6 B! X' W
],/ z0 _ A, l+ d" c0 A$ o8 U( S
"quorum": 1,
"signatures": null,
"type": "raw_tx_signature"0 M; R0 q* D. J, s- x
},
{
"type": "data",
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419"
}1 o* T. F# H$ j0 a5 R, v
]
}% c0 J& I: h$ s, g: J
]/ V- m- ~% c$ W
}
}
对应响应对象的源代码如下:# y% c8 ^5 F! p |/ E. i
type request struct{" n( |7 r0 S* i0 m6 u3 I% x
TxTemplate txbuilder.Template `json:"transaction_template"`
}. E7 }; Q1 W% O# p
// Template represents a partially- or fully-signed transaction.
type Template struct {
Transaction *types.Tx `json:"raw_transaction"`
SigningInstructions []*SigningInstruction `json:"signing_instructions"`
// AllowAdditional affects whether Sign commits to the tx sighash or
// to individual details of the tx so far. When true, signatures
// commit to tx details, and new details may be added but existing
// ones cannot be changed. When false, signatures commit to the tx9 i6 {: f. B1 R% q5 C7 H
// as a whole, and any change to the tx invalidates the signature.
AllowAdditional bool `json:"allow_additional_actions"`
}) S, C& x. d! d; h- r
其中TxTemplate相关字段的说明见build-transaction的结果描述) w) |4 u m- {* g) Q
调用estimate-transaction-gas接口成功之后返回的json结果如下:
{
"total_neu": 5000000,
"storage_neu": 3840000,; n/ u, {5 D" P- M# _5 W
"vm_neu": 1419000# }, }4 M& y4 M+ H5 p
}) r, o) i% u2 b% }& t6 {! H5 @- c
对应响应对象的源代码如下:
// EstimateTxGasResp estimate transaction consumed gas! Z0 C5 g. \8 b* r- E+ t
type EstimateTxGasResp struct {
TotalNeu int64 `json:"total_neu"`+ S" o& \; u9 [: }" o" p1 e
StorageNeu int64 `json:"storage_neu"`- q. F* W& ]5 p( \3 h$ Z
VMNeu int64 `json:"vm_neu"`
}
结构字段说明如下:
TotalNeu 预估的总手续费(单位为neu),该值直接加到build-transaction的BTM资产输入action中即可2 N& ~: p4 G# e% a: d
StorageNeu 存储交易的手续费, N" U* p( j! [4 }
VMNeu 运行虚拟机的手续费" V3 G- T, w+ D& R s
2、签名交易8 I% f4 e6 E5 t' N% x& b1 f
API接口 sign-transaction,代码api/hsm.go#L53
签名交易的输入请求json格式如下:4 P5 o6 i$ w; C6 F! r4 {
{$ \2 V5 r% s3 n7 V
"password": "123456",
"transaction": {
"allow_additional_actions": false,
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a077301000161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf456010003013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100",; \! s9 s# x1 T, o7 M
"signing_instructions": [
{
"position": 0,
"witness_components": [' a( y4 x( z, I1 S
{, n+ o3 z" e# U( S: l. [) P
"keys": [
{
"derivation_path": [
"010100000000000000",+ Z0 `, a v7 ?7 u% C% f
"0100000000000000"8 t9 Q( ~1 G) d
],' x2 P* N& ]2 ~( [* P. t" d O
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"! H5 g d# Q5 e) r# ~9 t! U
}" `( D1 ^9 K- G8 P$ Y* Q, B
],
"quorum": 1,
"signatures": null,; g" E$ n8 Q: g2 `
"type": "raw_tx_signature"3 E: M. E# m W9 S5 t
},
{
"type": "data",$ b' p5 p4 I4 F1 H# u8 p* |
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"
}
]
},
{
"position": 1,
"witness_components": [' v( H$ \& H4 Q8 @
{! J, W- |1 H3 B) _* v7 p% }
"keys": [
{
"derivation_path": [9 Z; ~3 ?, Y* M' ~! O" r+ C# Y2 ^' ^
"010100000000000000",6 S* _" D; L& g+ f3 U
"0800000000000000"5 K) T4 y$ B" C9 Y+ W1 O/ |
],0 C$ p+ j$ I h& z+ j. K4 r, `
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"6 D6 M, X5 A' `$ R
}
],
"quorum": 1,
"signatures": null,
"type": "raw_tx_signature"
},
{/ R2 h$ a0 m J3 K0 y
"type": "data",
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419"
}
]
}3 @- ~( g J" w c; [
]
}
}& Y/ a3 I6 {; A( h' e
对应请求对象的源代码如下:
type SignRequest struct { //function pseudohsmSignTemplates request' N2 U1 r) D9 ^- O
Password string `json:"password"`& n4 w9 D2 o& z$ j
Txs txbuilder.Template `json:"transaction"`
}
结构字段说明如下:
Password 签名的密码,根据密码可以从节点服务器上解析出用户的私钥,然后用私钥对交易进行签名5 F2 C8 O% u1 [+ q7 N
Txs 交易模板,build-transaction的返回结果,结构类型为 txbuilder.Template,相关字段的说明见build-transaction的结果描述" ]/ I* N/ A9 R7 D2 y2 g# h; S
# ]. }) F+ Q' U! H, a( j" _
签名交易sign-transaction请求成功之后返回的json结果如下:5 i3 R L! C: D7 G
{( J; r% o, P( d1 e% X: r1 L I
"sign_complete": true,
"transaction": {
"allow_additional_actions": false,$ W" F3 x! U' ^& K
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a0773630240273d5fc4fb06909fbc2968ea91c411fd20f690c88e74284ce2732052400129948538562fe432afd6cf17e590e8645b80edf80b9d9581d0a980d5f9f859e3880620d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd50161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf4566302400cf0beefceaf9fbf1efadedeff7aee5b38ee7a25a20d78b630b01613bc2f8c9230555a6e09aaa11a82ba68c0fc9e98a47c852dfe3de851d93f9b2b7ce256f90d2005cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe6154053541903013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100",0 w* Y) k$ Y( m
"signing_instructions": [
{
"position": 0,% A b; f! D" I4 I1 N' m/ L% G' R
"witness_components": [8 |. w' ~4 }5 S+ P; _
{
"keys": [5 V- ~( o" t* Q9 d# Y6 Q" n
{$ ~/ J+ O9 o5 J5 o9 x9 O: X
"derivation_path": [
"010100000000000000",
"0100000000000000"4 F) j% _8 H) X- D' E; j
],, D X0 S; G- l- C
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}
],! z6 _1 X/ s3 c* ^
"quorum": 1,* h2 G/ E5 ?! v( ?: E
"signatures": [/ W! ^- [% P0 X% @! D
"273d5fc4fb06909fbc2968ea91c411fd20f690c88e74284ce2732052400129948538562fe432afd6cf17e590e8645b80edf80b9d9581d0a980d5f9f859e38806": m6 _$ c5 w( s% B, q. i
],
"type": "raw_tx_signature"# a( w7 ?* g& ?& `$ Z
},) P Q: i! `6 M$ K) A: u3 S
{
"type": "data",
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"
}. X* c+ ~" R$ n3 f- n
]
},# I! r, W4 G4 ?0 |" i
{! l: B" a; |; Z8 {5 [& i0 l
"position": 1,
"witness_components": [
{
"keys": [$ {4 W8 u+ ~) Z, _# Z
{
"derivation_path": [. T) F% o# O* c, m
"010100000000000000",
"0800000000000000"
],0 Q' {9 h0 X( \7 F6 \0 X: h! D
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8": C9 \. ]+ j, F7 {" Z* F
}& T5 b3 j+ p' a @5 T% L# t* K j- Q
],
"quorum": 1,
"signatures": [
"0cf0beefceaf9fbf1efadedeff7aee5b38ee7a25a20d78b630b01613bc2f8c9230555a6e09aaa11a82ba68c0fc9e98a47c852dfe3de851d93f9b2b7ce256f90d"
],
"type": "raw_tx_signature"
},
{2 [/ v: I9 R0 ]- v
"type": "data",4 m7 X* Y8 {" v/ u' o
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419"2 B5 Y1 P, C- f. P4 @
}
]& ~* o: C+ N$ S% s; p* S
}" B: |' D; L3 g4 f' K4 b
]' S: Q G$ k% i F" ]3 ^
} \: t4 Y6 T% ~8 @& h; ]! Y, x. J: j
}
对应响应对象的源代码如下:( t- M9 l1 K9 M; l$ M7 d# ~3 d
type signResp struct {
Tx *txbuilder.Template `json:"transaction"`
SignComplete bool `json:"sign_complete"`
}
结构字段说明如下:
Tx 签名之后的交易模板txbuilder.Template,如果签名成功则signatures会由null变成签名的值,而raw_transaction的长度会变长,是因为bc.Tx部分添加了验证签名的参数信息# f N$ U$ T# o# N
SignComplete 签名是否完成标志,如果为true表示签名完成,否则为false表示签名未完成,单签的话一般可能为签名密码错误; 而多签的话一般为还需要其他签名。签名失败只需将签名的交易数据用正确的密码重新签名即可,无需再次build-transaction构建交易
3、提交交易
API接口 submit-transaction,代码api/transact.go#L135
提交交易的输入请求json格式如下:
{, H' U8 ^7 T3 t1 h3 Z1 e& Z
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a0773630240273d5fc4fb06909fbc2968ea91c411fd20f690c88e74284ce2732052400129948538562fe432afd6cf17e590e8645b80edf80b9d9581d0a980d5f9f859e3880620d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd50161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf4566302400cf0beefceaf9fbf1efadedeff7aee5b38ee7a25a20d78b630b01613bc2f8c9230555a6e09aaa11a82ba68c0fc9e98a47c852dfe3de851d93f9b2b7ce256f90d2005cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe6154053541903013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100"
}+ u3 s$ H" `: S7 o7 W" J6 R9 s
对应源代码的请求对象如下:
type SubmitRequest struct { //function submit request
Tx types.Tx `json:"raw_transaction"`
}8 ?: T" H& \4 {+ A
结构字段说明如下:
Tx 签名完成之后的交易信息。这里需要注意该字段中的raw_transaction不是签名交易sign-transaction的全部返回结果,而是签名交易返回结果中transaction中的raw_transaction字段。
submit-transaction请求成功之后返回的json结果如下:; J* }5 D+ z0 N- f# R
{
"tx_id": "2c0624a7d251c29d4d1ad14297c69919214e78d995affd57e73fbf84ece361cd"
}
对应源代码的响应对象如下:
type submitTxResp struct {, h6 c8 w/ @! j* z" \8 a: K
TxID *bc.Hash `json:"tx_id"`
}
结构字段说明如下:
TxID 交易ID,当交易被提交到交易池之后会显示该信息,否则表示交易失败0 f0 o/ s; d! g' }8 z0 o
成为第一个吐槽的人