Bytom交易说明(账户管理模式)
V刘晨曦
发表于 2022-11-13 23:52:49
115
0
0
Github地址:https://github.com/Bytom/bytom: `/ d) U \2 H( n: G
Gitee地址:https://gitee.com/BytomBlockchain/bytom# F1 \5 Z% q+ }' n: ~
该部分主要针对用户使用bytom自带的账户模式发送交易& x+ Y- ]# e& o/ P* K+ r
1、构建交易6 p' p( Y; T5 B- Z
API接口 build-transaction,代码api/transact.go#L120
以标准的非BTM资产转账交易为例,资产ID为全F表示BTM资产,在该示例中BTM资产仅作为手续费,该交易表示花费99个特定的资产到指定地址中。其中构建交易的输入请求json格式如下:
{
"base_transaction": null,4 h) j" S- Y# _, B0 @+ m
"actions": [/ R6 M( H( l2 O `+ i( X
{9 N, L* @/ T" v& G8 d9 a+ R4 y
"account_id": "0ER7MEFGG0A02",0 x- t E% I+ ~6 P4 D
"amount": 20000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"type": "spend_account"
},8 o6 }) u3 E, s+ H; X9 d6 [
{
"account_id": "0ER7MEFGG0A02",, q3 Z- I! e) K0 `+ a* R% E7 d) o. r; o
"amount": 99, B7 s& F# B0 O, Q# Y6 Y( v2 S$ E
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f",
"type": "spend_account"
},: r/ i* p3 `1 @% t) I) P( I9 M
{: t1 J5 t1 f! ]- {4 T1 n0 X
"amount": 99,; p j) z2 T, D+ @7 c+ C# T, i
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f",
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",& A7 ^: y& D' H' g+ B
"type": "control_address"
}. [! f" A# \# a) Y' l! n
],
"ttl": 0,
"time_range": 02 [4 V' m# K# N. B$ }
}5 z: d: u0 W' ]8 X) u O
对应源代码的请求对象如下:
// BuildRequest is main struct when building transactions
type BuildRequest struct {0 Y. z L6 Y* @# j5 L' U' ?
Tx *types.TxData `json:"base_transaction"`2 _" M9 a- m7 U' R/ T0 Q' q) _$ |; `5 H6 K
Actions []map[string]interface{} `json:"actions"`1 {0 R$ L, ~- M* @
TTL json.Duration `json:"ttl"`
TimeRange uint64 `json:"time_range"`
}
结构字段说明如下:
Tx 交易的TxData部分,该字段为预留字段,为空即可
TTL 构建交易的生存时间(单位为毫秒),意味着在该时间范围内,已经缓存的utxo不能用于再一次build交易,除非剩余的utxo足以构建一笔新的交易,否则会报错。当ttl为0时会被默认设置为600s,即5分钟9 N. a, e6 x1 X {; h
TimeRange 时间戳,意味着该交易将在该时间戳(区块高度)之后不会被提交上链,为了防止交易在网络中传输延迟而等待太久时间,如果交易没有在特定的时间范围内被打包,该交易便会自动失效
Actions 交易的actions结构,所有的交易都是由action构成的,map类型的interface{}保证了action类型的可扩展性。其中action中必须包含type字段,用于区分不同的action类型,action主要包含input和output两种类型,其详细介绍如下:. E- c4 b& {! `
input action 类型:2 r5 N. o }+ B4 z/ O
issue 发行资产6 H7 m5 v3 E) m5 t: h
spend_account 以账户的模式花费utxo
spend_account_unspent_output 直接花费指定的utxo
output action 类型:
control_address 接收方式为地址模式5 m* l" m; x, v- |9 k0 P6 \
control_program 接收方式为(program)合约模式
retire 销毁资产, j i+ L( N5 X1 {1 J- l- \
- x" ^) }' ? j8 d6 {2 j
8 \4 D7 v7 X$ s2 A, f; H4 p J
! R# k1 m4 t) J( d: a) E! H
注意事项: i* h6 z; E8 f) s2 q8 i- |' V: F
一个交易必须至少包含一个input和output(coinbase交易除外,因为coinbase交易是由系统产生,故不在此加以描述),否则交易将会报错。
除了BTM资产(所有交易都是以BTM资产作为手续费)之外,其他资产在构建input和output时,所有输入和输出的资产总和必须相等,否则交易会报出输入输出不平衡的错误信息。
交易的手续费: 所有inputs的BTM资产数量 - 所有outputs的BTM资产数量
交易中的资产amount都是neu为单位的,BTM的单位换算如下:1 BTM = 1000 mBTM = 100000000 neu# y3 L/ u5 j$ i# L
action简介6 y* s* T7 y, c- N
下面对构建交易时用到的各种action类型进行详细说明:
issue$ A, V S8 g! Z5 C }9 w2 x+ b
issueAction结构体源代码如下:8 C0 J& O6 m; y6 ~5 n- C& ]
type issueAction struct {' X0 a8 y& U* I% Y4 X' f* D% r+ M
assets *Registry0 h; @3 g4 _! o6 H# ?+ c7 D, J6 j
bc.AssetAmount
}
type AssetAmount struct {
AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"`) P9 g5 s% Q, s D2 d
Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"`
}
结构字段说明如下:
assets 主要用于资产的管理,无需用户设置参数7 ~" b4 Q+ Q( w" M1 u5 Z
AssetAmount 表示用户需要发行的资产ID和对应的资产数目,这里的AssetID需要通过create-asset创建,并且这里不能使用BTM的资产ID
issueAction的json格式为:
{/ ^- K9 F' M, p- D# c1 }8 k
"amount": 100000000,
"asset_id": "3152a15da72be51b330e1c0f8e1c0db669269809da4f16443ff266e07cc43680",
"type": "issue"
}
例如发行一笔资产的交易示例如下:
(该交易表示发行数量为900000000个assetID的42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f的资产到接收地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费为20000000neu的BTM资产)
{
"base_transaction": null,
"actions": [; B9 N8 a+ r+ x. v
{) f- }2 D+ ^7 ]
"account_id": "0ER7MEFGG0A02",
"amount": 20000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"type": "spend_account"
},
{* B2 m" u( {7 |; S6 c% ~% K
"amount": 900000000,) N. S' j/ d2 X5 r S5 V y
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f",# ]8 ?& F v; p8 c! E8 v: @9 Z: h; Q5 x
"type": "issue"
},( A+ ?0 _: b3 H; h# S) e
{
"amount": 900000000,9 q0 {- | R; @4 ?! [, G
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f"," l. I5 q$ y* W ]) A8 S
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",
"type": "control_address"
}
],; t4 M2 {- P( R9 N! D3 z }
"ttl": 0,. k, Y! v) C7 l3 f4 n
"time_range": 0: S5 _8 V. H Z9 _& i( _# V
}
J& N2 u0 h( W N
spend_account
spendAction结构体源代码如下:
type spendAction struct {7 t3 C& s2 }; c- E4 } `3 ^
accounts *Manager
bc.AssetAmount
AccountID string `json:"account_id"`
ClientToken *string `json:"client_token"`
}
type AssetAmount struct {/ F$ n2 g% U% P# ~4 \
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"`
}
结构字段说明如下:+ k9 M+ n% K& T5 E" U0 \# q9 O
accounts 主要用于账户的管理,无需用户设置参数
AccountID 表示需要花费资产的账户ID
AssetAmount 表示花费的资产ID和对应的资产数目1 |9 r& ?2 e* J$ ?6 w5 |/ H
ClientToken 表示Reserve用户UTXO的限制条件,目前不填或为空即可
spendAction的json格式为:
{3 O! c% @" ~! U' z Y
"account_id": "0BF63M2U00A04",
"amount": 2000000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"type": "spend_account"* x1 R0 s8 Y" u; Q$ F3 ~' y% g! _9 Z" \
}
例如转账一笔资产的交易示例如下:
(该交易表示通过账户的方式转账100000000neu的BTM资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费20000000neu = 输入BTM资产数量 - 输出BTM资产数量)
{9 y* L# X S* R+ |. i$ f( _
"base_transaction": null,
"actions": [
{$ r+ u& Z l: `& o( h/ ^; n
"account_id": "0ER7MEFGG0A02",
"amount": 120000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",6 {, ^7 I( P! Z' g5 S1 T8 a3 W
"type": "spend_account"5 o* k2 y3 K( W. O
},
{. n1 u/ L2 x/ y ^3 p' U
"amount": 100000000,0 _. X( P8 J8 W* _2 f
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",; }7 v; y- D' Z. {) H
"type": "control_address"
}# G+ k1 _; A2 |* `0 z v [6 e
],
"ttl": 0,) T* ~ d m: K) r
"time_range": 00 h8 k6 Q- m% k: F& J4 [6 [
}
. [! ~3 ?& _' M% b( k: P
spend_account_unspent_output% t# t3 G& }9 k- v& X% `
spendUTXOAction结构体源代码如下:
type spendUTXOAction struct {
accounts *Manager/ |3 ^' Y7 s1 s$ n
OutputID *bc.Hash `json:"output_id"`
ClientToken *string `json:"client_token"`
}6 K3 c2 {' A3 y8 d; \
结构字段说明如下:3 o% {$ l( X+ G, B* N4 Q, r
accounts 主要用于账户的管理,无需用户设置参数
OutputID 表示需要花费的UTXO的ID,可以根据list-unspent-outputs查询可用的UTXO,其中OutputID对应该API返回结果的id字段+ W- }9 X4 [& E* S4 }
ClientToken 表示Reserve用户UTXO的限制条件,目前不填或为空即可3 {# T+ f$ C2 A
7 o! J X0 w& P5 b V
spendUTXOAction的json格式为:
{
"type": "spend_account_unspent_output",- l+ y( b2 U) g! M: }6 S0 F C
"output_id": "58f29f0f85f7bd2a91088bcbe536dee41cd0642dfb1480d3a88589bdbfd642d9"
}" `) a# p I8 e: N) v6 S3 D( E
例如通过花费UTXO的方式转账一笔资产的交易示例如下:
(该交易表示通过直接花费UTXO的方式转账100000000neu的BTM资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费 = 输入BTM资产的UTXO值 - 输出BTM资产数量)" K$ T3 t$ u: z0 L) s
{
"base_transaction": null,$ Z( s* m: x& O
"actions": [
{
"output_id": "58f29f0f85f7bd2a91088bcbe536dee41cd0642dfb1480d3a88589bdbfd642d9",3 _/ \7 H. G' f' N5 Z! _ a
"type": "spend_account_unspent_output"' \* a; r0 E. _4 G4 K
},
{2 Z( g8 }9 e) l7 ^ z
"amount": 100000000, K/ H4 w5 M# W P, a
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",4 K7 I% {. H: [
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",
"type": "control_address"
}
],
"ttl": 0,
"time_range": 06 v: I! t' J4 b* \- z" ^
}
control_address
controlAddressAction结构体源代码如下:, j2 Z8 N. ?/ r$ ~
type controlAddressAction struct {
bc.AssetAmount; d) t l* J" n, b
Address string `json:"address"`
}: c$ u$ P! j3 I" z2 ?# c. o
type AssetAmount struct {
AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"`$ y' s$ t* E( P
Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"`8 T$ X9 s7 |' I; k4 W1 z0 J
}% Y/ a1 [5 B, j: v0 x
结构字段说明如下:* j+ f2 s9 H/ x( ]- g' D3 z" Q3 U
Address 表示接收资产的地址,可以根据 create-account-receiver API接口创建地址
AssetAmount 表示接收的资产ID和对应的资产数目% R; W0 U# Q- P! `7 Z% a' i
3 |" K* m; b; t9 t9 D
controlAddressAction的json格式为:6 x% o& V! J4 ?- m5 ]% J/ o
{
"amount": 100000000,6 @- c4 P _( k4 y+ Z% V! O1 A- D
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",% j6 @' k! A7 y7 X5 a; n8 c
"address": "bm1q50u3z8empm5ke0g3ngl2t3sqtr6sd7cepd3z68",7 }" `' X7 {; l6 i5 ?
"type": "control_address"
}# u. U( u) I0 ^& ]4 P
例如转账一笔资产的交易示例如下:
(该交易表示通过账户的方式转账100000000neu的BTM资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中control_address类型表示以地址作为接收方式)8 {. b& p6 A: W9 _; Q' l0 X$ E
{5 T- K) J* X. q! Y" i3 P* z+ D) I
"base_transaction": null,6 k1 F# O1 l0 |. f
"actions": [
{8 i L! E3 d( J
"account_id": "0ER7MEFGG0A02",
"amount": 120000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"type": "spend_account"
},
{0 Y8 t, S% H% s+ f
"amount": 100000000,4 O7 Q0 h) |$ v8 O" i
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",5 w2 h6 h; P: r6 z3 Q
"type": "control_address": e$ C" I7 k" x8 V8 o L' j6 E
}
],- A8 v% }1 S, \, ~6 y+ X
"ttl": 0,
"time_range": 03 B* o" Y' x( C! J
}" m/ v v2 `' o% t' I8 S
( `7 i! h" \* |& {( {
control_program
controlProgramAction结构体源代码如下:
type controlProgramAction struct {# s+ c' x# a9 w6 Z
bc.AssetAmount7 |* _# ~2 [: Y# s& S) y/ d
Program json.HexBytes `json:"control_program"`/ B4 f$ k9 M& T; ^0 C6 I
}
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"`' c& A" y! A# C: d# a3 O
}
结构字段说明如下:
Program 表示接收资产的合约脚本,可以根据 create-account-receiver API接口创建接收program(返回结果的 program 和 address 是一一对应的)
AssetAmount 表示接收的资产ID和对应的资产数目
controlProgramAction的json格式为:7 P) q- r. R+ ? ^+ o& R% P! \2 K' |
{3 @! l* q4 L9 M- p
"amount": 100000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"control_program":"0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19",
"type": "control_program"
}
例如转账一笔资产的交易示例如下:
(该交易表示通过账户的方式转账100000000neu的BTM资产到接收program(跟address是一一对应的)0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19中, 其中control_program类型表示以program作为接收方式)
{
"base_transaction": null,# S* [( W3 \. }1 I* W
"actions": [ |' }% B1 w* J# j
{
"account_id": "0ER7MEFGG0A02",' z+ A1 ~% g; E0 N2 J* f) u# w
"amount": 120000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",' M. P! J( Y B$ x0 V/ m
"type": "spend_account"
},
{0 B s1 c5 |9 F7 ~
"amount": 100000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"control_program": "0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19",3 n* v$ ?8 C6 A3 O# ?5 X9 u
"type": "control_program"
}
],
"ttl": 0,
"time_range": 0
}) v, }0 [& ^9 Y! @. `
retire
retireAction结构体源代码如下:
type retireAction struct {
bc.AssetAmount
}4 Q6 b# F# j) z4 X; p: s% t' }3 d0 g
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"`, q0 _& ]5 i/ s# w3 {; X
}, ~' b9 N- l& q# d, f
结构字段说明如下:5 ~0 T$ L' i" l$ M/ [) s
AssetAmount 表示销毁的资产ID和对应的资产数目6 o4 B, X0 G$ u$ }& U
: m$ X9 a0 g- B: t
retireAction的json格式为:, N; f2 y2 Y9 r
{
"amount": 900000000,# ^5 N% A, l" X# g
"asset_id": "3152a15da72be51b330e1c0f8e1c0db669269809da4f16443ff266e07cc43680",# ^/ {) V( |, R$ N6 D7 T! q9 w
"type": "retire"* w* Z6 l1 [' R. e4 s+ R. X. K6 T
}
例如销毁一笔资产的交易示例如下:
(该交易表示通过账户的方式将100000000neu的BTM资产销毁, retire表示销毁指定数量的资产)
{7 n5 ~. I: s$ ]( X, e. ]7 i, X
"base_transaction": null,
"actions": [
{
"account_id": "0ER7MEFGG0A02",9 J4 o, x# K* A( ~9 b9 N: H [
"amount": 120000000,0 q. S1 z3 }& u
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"type": "spend_account"2 u8 s. _0 U7 s/ c; O. u' T$ M# f
},3 I2 [' A5 @8 Z4 h
{% s8 ^0 x: z( N+ m3 g3 A
"amount": 100000000,% J* S+ n( N! p6 l
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",1 `# a% M0 @6 ?0 V
"type": "retire": ^; B' p5 n$ B0 b+ [& S1 ~
} y1 `; Z- J4 k/ K8 |1 ~0 g+ S
],6 [7 V- e4 h& k
"ttl": 0,
"time_range": 0
}
) Y+ P5 v5 o3 N. a! W
build-transaction的输入构造完成之后,便可以通过http的调用方式进行发送交易,构建交易请求成功之后返回的json结果如下:& A( D* ?; x7 l- K* _( s+ u
{1 _* Y2 Q9 |+ P. R3 g2 {
"allow_additional_actions": false,' I* Z% B ? I3 ]0 X. _# V1 S( n' O
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a077301000161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf456010003013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100",
"signing_instructions": [
{2 X+ t: t0 A) i6 ^, v9 O) F3 k
"position": 0,! ^ U: P6 L3 p% J
"witness_components": [
{$ E$ }/ s' o) g6 [
"keys": [
{
"derivation_path": [
"010100000000000000",( C$ s( X/ ]* C& ?
"0100000000000000"
],/ h5 c! Q& v5 h5 b, f
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}
],
"quorum": 1,
"signatures": null,8 g6 }, x* @3 n) q, n" u7 }
"type": "raw_tx_signature"* P2 d0 @7 S6 A( L1 M9 T9 N
},6 Q3 X$ h9 G" ?$ X/ P4 [
{' v. f5 {2 {! @4 z( p9 o
"type": "data",) ^2 x- v" R8 t. h1 C- D
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"4 @: i* o- a6 a9 @
}$ R% N4 a/ G0 D% B% T3 [& M# j
]( { L) Q- j; E T8 S8 T
},8 E0 u' G: R9 L% M
{) M. n6 d# _0 l7 n
"position": 1,% h) T0 G" b( F& B/ W- ~ x
"witness_components": [
{
"keys": [3 z$ z5 j g, \. i N% S
{8 k( A" x8 Z7 }/ j6 }: z
"derivation_path": [
"010100000000000000",( E% u7 N& V4 T2 i! o6 i% w/ P
"0800000000000000"
],% S0 s% X5 w, ^( \, r7 C/ N6 k
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}4 O2 J2 C4 v& o
],6 j5 \: Q) e) o2 E5 F2 k0 b' o
"quorum": 1,
"signatures": null,
"type": "raw_tx_signature", k0 x9 |8 A- Y9 h) |& n
},
{6 X( M7 i$ T0 i( M$ k2 F+ g
"type": "data", H" A; I! W+ G* V
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419", [. p# ~% A1 M8 t
}: w O5 `) S. E! A2 V- b* Q! |
]& O/ T+ C" c/ A& D
}
]
}
对应响应对象的源代码如下:
// Template represents a partially- or fully-signed transaction.$ P& _1 T9 J( O1 a/ ~' ^! j
type Template struct { M7 c$ A2 t' d7 E5 \: ?% c
Transaction *types.Tx `json:"raw_transaction"`
SigningInstructions []*SigningInstruction `json:"signing_instructions"`( o# O, n) L# ^/ y, f& m
// AllowAdditional affects whether Sign commits to the tx sighash or# `0 j* Q! X" b! j* {
// to individual details of the tx so far. When true, signatures
// commit to tx details, and new details may be added but existing5 d3 I9 ~ Q* I2 H* F" r
// 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"`4 `8 f8 k* y; F; w% l9 i( Y8 q2 X
}
结构字段说明如下:
Transaction 交易相关信息,该字段包含TxData和bc.Tx两个部分:
TxData 表示给用户展示的交易数据部分,该部分对用户可见
Version 交易版本
SerializedSize 交易序列化之后的size, g7 H" z4 [5 a. N. G9 [4 N' l+ @
TimeRange 交易提交上链的最大时间戳(区块高度)(主链区块高度到达该时间戳(区块高度)之后,如果交易没有被提交上链,该交易便会失效)
Inputs 交易输入
Outputs 交易输出0 d! l. `3 h6 j! d: I5 w
bc.Tx 表示系统中处理交易用到的转换结构,该部分对用户不可见,故不做详细描述2 }0 k3 `8 `: T7 _
SigningInstructions 交易的签名信息; o) O# i2 N. q7 v) L
Position 对input action签名的位置7 T1 A4 q/ W1 J+ q7 C
WitnessComponents 对input action签名需要的数据信息,其中build交易的signatures为null,表示没有签名; 如果交易签名成功,则该字段会存在签名信息。该字段是一个interface接口,主要包含3种不同的类型:- u2 g; n7 y1 c
SignatureWitness 对交易模板Template中交易input action位置的合约program进行哈希,然后对hash值进行签名
signatures (数组类型)交易的签名,sign-transaction执行完成之后才会有值存在( j4 } Q* v# W8 K) v3 F9 @" _- N2 n, G% V
keys (数组类型)包含主公钥xpub和派生路径derivation_path,通过它们可以在签名阶段找到对应的派生私钥child_xprv,然后使用派生私钥进行签名% d1 y; H% v& I! l: |7 m$ y
quorum 账户key 的个数,必须和上面的keys的长度相等。如果quorum 等于1,则表示单签账户,否则为多签账户
program 签名的数据部分,program的hash值作为签名数据。如果program为空,则会根据当前交易ID和对应action位置的InputID两部分生成一个hash,然后把它们作为指令数据自动构造一个program5 F* o0 @9 j' M! o5 U
RawTxSigWitness 对交易模板Template的交易ID和对应input action位置的InputID(该字段位于bc.Tx中)进行哈希,然后对hash值进行签名# N4 u7 p* {+ A9 _; A- G7 L
signatures (数组类型)交易的签名,sign-transaction执行完成之后才会有值存在
keys (数组类型)包含主公钥xpub和派生路径derivation_path,通过它们可以在签名阶段找到对应的派生私钥child_xprv,然后使用派生私钥进行签名
quorum 账户key的个数,必须和上面的keys 的长度相等。如果quorum 等于1,则表示单签账户,否则为多签账户8 R& z/ N4 ?% ?8 ]- Z
DataWitness 该类型无需签名,验证合约program的附加数据
9 O" S5 ^" Y9 S$ s) H" s
AllowAdditional 是否允许交易的附加数据,如果为true,则交易的附加数据会添加到交易中,但是不会影响交易的执行的program脚本,对签名结果不会造成影响; 如果为false,则整个交易作为一个整体进行签名,任何数据的改变将影响整个交易的签名 ~7 u& w: y$ q* C( o1 Y/ a4 K
估算手续费
估算手续费接口estimate-transaction-gas是对build-transaction的结果进行手续费的预估,估算的结果需要重新加到build-transaction的结果中,然后对交易进行签名和提交。其主要流程如下: q8 _6 i: ?4 ~( \' _8 T6 ~1 \
build - estimate - build - sign - submit
估算手续费的输入请求json格式如下:
{
"transaction_template": {5 }! P0 g. ^( l8 e- i
"allow_additional_actions": false,
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a077301000161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf456010003013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100",1 C; s3 \6 ? G
"signing_instructions": [6 G9 x$ A2 H" b9 A7 W
{' z9 ]) H k+ `" R( M% e
"position": 0,) U/ P& S4 e [6 h9 V+ ~9 p
"witness_components": [
{: p9 m s. ~9 q& l& ]& n3 T2 q
"keys": [' G3 E& P2 U7 d9 n2 V. b6 Q5 E
{
"derivation_path": [8 x5 k0 n6 f+ @! a
"010100000000000000",( t s( w. V" [6 W& o
"0100000000000000"
],/ _4 v- q, w! Y6 R
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}
],
"quorum": 1,
"signatures": null,$ n, V$ ~# ?4 ^3 X
"type": "raw_tx_signature"
},8 ~; h e# O3 N5 [$ V( K
{
"type": "data",5 F( N- a; `1 O+ o
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"6 K; I$ K4 b& q, J
}
]& l8 J: L, T0 L' _! u
},
{' M& l5 i5 |6 r. F, t* s
"position": 1,: E" R! L; j" P1 t9 s7 d2 t
"witness_components": [% T8 p" m# o4 {
{5 o' \4 T( d$ Z6 F) V" h
"keys": [2 F7 F" k: T0 i7 M* _- Z$ y) y
{
"derivation_path": [2 P' M8 u3 q [% N7 n
"010100000000000000",+ ` E2 j+ g; E# p' f
"0800000000000000"
],# l+ D& \0 S z7 N+ k. C$ r0 x& X
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}
],
"quorum": 1,
"signatures": null,
"type": "raw_tx_signature"
},9 a& M `: w& [& \+ m
{
"type": "data",5 O# q3 ^' }7 u
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419"
}% v6 l1 h8 Y4 L! e. F h
]" X& D/ }) I! T6 O N
}; u) ~2 d, D" [/ I
]
}
}
对应响应对象的源代码如下:2 Y, _# j+ e" z8 S3 X+ k* C
type request struct{; }% ]3 w& H$ }6 r3 W
TxTemplate txbuilder.Template `json:"transaction_template"`
}- L6 a+ W9 p& ~0 K$ q! |
// Template represents a partially- or fully-signed transaction.
type Template struct {( R* ?- _8 R) b
Transaction *types.Tx `json:"raw_transaction"`
SigningInstructions []*SigningInstruction `json:"signing_instructions"`
// AllowAdditional affects whether Sign commits to the tx sighash or+ d7 }+ N- t2 W5 `
// to individual details of the tx so far. When true, signatures5 {5 v6 y5 ]* J/ ^. F7 `
// commit to tx details, and new details may be added but existing( t ~7 w x+ z
// 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"`% T/ A' b5 H6 c9 K0 T+ m7 h% x
}5 R6 X# l5 x9 x& I
其中TxTemplate相关字段的说明见build-transaction的结果描述
调用estimate-transaction-gas接口成功之后返回的json结果如下:7 @/ \# F8 w1 Y/ `6 ?& {" }- x* C
{
"total_neu": 5000000,
"storage_neu": 3840000,4 d( p" o9 ~. M9 V6 o# s& b
"vm_neu": 1419000
}- y- W W' j6 q& D/ ^0 l- M& ?: ^7 I
对应响应对象的源代码如下:
// EstimateTxGasResp estimate transaction consumed gas5 e( S* I& ^. g9 H* O/ H4 O
type EstimateTxGasResp struct {
TotalNeu int64 `json:"total_neu"`1 T; f. u& ~3 B0 s2 T( _
StorageNeu int64 `json:"storage_neu"`" ~' R0 j8 F% N" P% e6 _
VMNeu int64 `json:"vm_neu"`
}
结构字段说明如下:
TotalNeu 预估的总手续费(单位为neu),该值直接加到build-transaction的BTM资产输入action中即可
StorageNeu 存储交易的手续费
VMNeu 运行虚拟机的手续费
2、签名交易% v* I, y5 G$ a' _5 p
API接口 sign-transaction,代码api/hsm.go#L53/ Q* l* x: `5 t4 y
签名交易的输入请求json格式如下:6 a& p* C g2 u! M
{, O$ B/ i: y8 `% H+ U. A2 Z
"password": "123456",+ O* U7 F' n: ]5 x8 u! x& }( Y
"transaction": {
"allow_additional_actions": false,4 L- \% y: w8 u( s6 b
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a077301000161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf456010003013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100", A1 h0 E5 r1 V7 f* g
"signing_instructions": [2 D# m. W9 j: S7 v3 ?3 V6 _# [
{
"position": 0,/ _, h3 A6 q- } w) f9 r
"witness_components": [! @' D3 t. f6 T3 o0 N$ O
{
"keys": [2 Q. n; T1 @" q6 E
{6 h+ I5 |' Q( u5 g, `& b: M+ O! @1 ~
"derivation_path": [
"010100000000000000",
"0100000000000000"1 `" U6 P* I4 n, T! E0 U9 {
],/ K6 {' @2 T# k0 a. M* Q4 t
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}
],0 V& y0 a5 r- F! d/ o9 p5 n' a! |1 W2 t
"quorum": 1,
"signatures": null,8 h! C/ P6 |: w/ v' I
"type": "raw_tx_signature"5 ]1 d9 k; A4 g% Z
},
{
"type": "data",9 ^" M1 K* }8 O0 v1 y( o( C
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"( L. Y9 p$ t* j. O( H
}4 G/ L+ @% C a: F# o. ~9 D" ^
]
},2 H b2 D) Q1 _- W) l8 s
{8 \( O1 f& c H; j* h3 f2 u
"position": 1,3 P* |- h# O+ ] {
"witness_components": [, R/ b7 e8 l* [2 z5 U3 y
{
"keys": [
{
"derivation_path": [
"010100000000000000",
"0800000000000000"
],) ?; ~" ]5 [$ @$ ?9 T2 V
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"4 x, h! R) z' x7 @, ^7 _2 l# p5 R
}
],
"quorum": 1,! @8 j) ?* w; W! r( Z5 d
"signatures": null,3 \2 a2 e( p8 ^: g. W+ Z8 r/ }
"type": "raw_tx_signature"
},0 ~ q# ]8 A+ V' P1 J# B8 U) A" ]
{
"type": "data",, k. I; H2 g0 |5 d
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419"
}
]0 {7 j* N8 l; z7 h' o
}' e0 e/ ^( U D% t' g
]5 b: w% f* B2 o# H' ^
}- i" e9 m# W, x2 x6 N' w Q+ ` N0 Z
}
对应请求对象的源代码如下:* G d1 ` J, m' o5 U
type SignRequest struct { //function pseudohsmSignTemplates request, m( ~3 F, T7 K' Q
Password string `json:"password"`
Txs txbuilder.Template `json:"transaction"`
}
结构字段说明如下:
Password 签名的密码,根据密码可以从节点服务器上解析出用户的私钥,然后用私钥对交易进行签名
Txs 交易模板,build-transaction的返回结果,结构类型为 txbuilder.Template,相关字段的说明见build-transaction的结果描述) j( ?. Y6 h" y/ m" @) s2 h9 ^
签名交易sign-transaction请求成功之后返回的json结果如下:
{
"sign_complete": true,; ?$ w6 ?0 s& f# F, a* A/ ^
"transaction": {
"allow_additional_actions": false,5 }9 [. h, h9 X+ r+ w2 ?
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a0773630240273d5fc4fb06909fbc2968ea91c411fd20f690c88e74284ce2732052400129948538562fe432afd6cf17e590e8645b80edf80b9d9581d0a980d5f9f859e3880620d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd50161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf4566302400cf0beefceaf9fbf1efadedeff7aee5b38ee7a25a20d78b630b01613bc2f8c9230555a6e09aaa11a82ba68c0fc9e98a47c852dfe3de851d93f9b2b7ce256f90d2005cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe6154053541903013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100",
"signing_instructions": [
{8 B+ {$ ]8 K3 s; I+ T
"position": 0,! P# }# T5 P2 K
"witness_components": [
{
"keys": [
{
"derivation_path": [
"010100000000000000",
"0100000000000000"( s7 A0 O: q1 C5 {* F8 C
],5 r0 O6 |" D; T4 h! G$ q3 D% _" E
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"; x. |# Q t3 ~' `
}
],9 D' Z' e& h% Y2 o1 u
"quorum": 1,
"signatures": [5 z1 E5 T* Z, u X% K
"273d5fc4fb06909fbc2968ea91c411fd20f690c88e74284ce2732052400129948538562fe432afd6cf17e590e8645b80edf80b9d9581d0a980d5f9f859e38806"
],4 T* x7 K! e8 B# R% [$ J# ?
"type": "raw_tx_signature"7 [( l! }1 X7 a9 `0 c# u- T0 D( `8 C
},6 W8 f9 j" L. V/ O* B" E& _
{
"type": "data",( ^/ G" {- a5 Z5 k, a7 g3 v
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"
}
]
},3 ~% C- W6 B$ o
{
"position": 1,
"witness_components": [
{
"keys": [* Y% t& I) r* I0 {
{% [( r; F+ p( a2 s D. c: e, f
"derivation_path": [& E8 T( @: R. p0 ]& E" b! b- b# b
"010100000000000000",
"0800000000000000"
],/ `. L0 R0 N5 p$ H, k
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}$ T3 A6 ]- i F5 V5 g+ B9 x
],/ T# N; v0 J& }8 I7 C. N8 }. F
"quorum": 1,
"signatures": [# {3 X, X) _% \, u+ D0 ^
"0cf0beefceaf9fbf1efadedeff7aee5b38ee7a25a20d78b630b01613bc2f8c9230555a6e09aaa11a82ba68c0fc9e98a47c852dfe3de851d93f9b2b7ce256f90d"( ]8 J! Z( z* b& ], R
],1 C8 `% x! u* L1 p5 z
"type": "raw_tx_signature"
},0 S* S& i* ~- s. R( y4 Q
{/ N' {' k; D6 K- g8 B; g' w. t' M
"type": "data",
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419"
}
]
} x) |$ G! G. f' [
]
}
}
对应响应对象的源代码如下:
type signResp struct {
Tx *txbuilder.Template `json:"transaction"`
SignComplete bool `json:"sign_complete"`
}2 {( @0 R/ S* H [
结构字段说明如下:, ]+ E3 c2 x% n+ ^! E$ D
Tx 签名之后的交易模板txbuilder.Template,如果签名成功则signatures会由null变成签名的值,而raw_transaction的长度会变长,是因为bc.Tx部分添加了验证签名的参数信息7 M% b6 j# \, `5 K* w& E* f- k0 U3 Q
SignComplete 签名是否完成标志,如果为true表示签名完成,否则为false表示签名未完成,单签的话一般可能为签名密码错误; 而多签的话一般为还需要其他签名。签名失败只需将签名的交易数据用正确的密码重新签名即可,无需再次build-transaction构建交易3 X' }- z- u6 ^' z; G, Y
3、提交交易3 `4 u8 Z! w. p1 b# t8 g" h6 g
API接口 submit-transaction,代码api/transact.go#L135! q6 e r! N5 N( U. r3 W9 `( I
提交交易的输入请求json格式如下:1 G ]9 C2 H) f
{3 }1 {2 d& I; j/ J! E1 ]
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a0773630240273d5fc4fb06909fbc2968ea91c411fd20f690c88e74284ce2732052400129948538562fe432afd6cf17e590e8645b80edf80b9d9581d0a980d5f9f859e3880620d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd50161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf4566302400cf0beefceaf9fbf1efadedeff7aee5b38ee7a25a20d78b630b01613bc2f8c9230555a6e09aaa11a82ba68c0fc9e98a47c852dfe3de851d93f9b2b7ce256f90d2005cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe6154053541903013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100"
}
对应源代码的请求对象如下:
type SubmitRequest struct { //function submit request
Tx types.Tx `json:"raw_transaction"`
}
结构字段说明如下:
Tx 签名完成之后的交易信息。这里需要注意该字段中的raw_transaction不是签名交易sign-transaction的全部返回结果,而是签名交易返回结果中transaction中的raw_transaction字段。: G3 g% d% N! F6 V! x' s' R
submit-transaction请求成功之后返回的json结果如下:
{
"tx_id": "2c0624a7d251c29d4d1ad14297c69919214e78d995affd57e73fbf84ece361cd"0 E1 a1 Q( }; I: M& d
}
对应源代码的响应对象如下:
type submitTxResp struct { | Z( V( P) M7 [6 W4 \
TxID *bc.Hash `json:"tx_id"`; C+ ` Z8 R, b$ p' j
}2 O: o& k. {8 k4 S- R
结构字段说明如下:
TxID 交易ID,当交易被提交到交易池之后会显示该信息,否则表示交易失败4 K9 l2 ~ A2 T3 e( a% _
成为第一个吐槽的人