Bytom交易说明(账户管理模式)
V刘晨曦
发表于 2022-11-13 23:52:49
173
0
0
Github地址:https://github.com/Bytom/bytom
Gitee地址:https://gitee.com/BytomBlockchain/bytom
该部分主要针对用户使用bytom自带的账户模式发送交易
1、构建交易
API接口 build-transaction,代码api/transact.go#L120
以标准的非BTM资产转账交易为例,资产ID为全F表示BTM资产,在该示例中BTM资产仅作为手续费,该交易表示花费99个特定的资产到指定地址中。其中构建交易的输入请求json格式如下:
{
"base_transaction": null,- ^8 S. z, R( T9 [
"actions": [
{
"account_id": "0ER7MEFGG0A02",
"amount": 20000000,8 y7 o: D( x9 B
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",8 ?. c- g: m. H* C
"type": "spend_account"
},: p+ [- c# u7 ?7 f& ]
{4 g2 y9 |# ]6 q2 I+ d, S y$ T
"account_id": "0ER7MEFGG0A02",6 ]1 l* k# p& v0 U
"amount": 99,
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f",
"type": "spend_account"2 Q3 x% J8 f0 @+ t+ d' Z" r6 L; Q4 h
},
{
"amount": 99,
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f",
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",
"type": "control_address"
}
],7 s' u E) ?' G$ i9 H- g0 m
"ttl": 0,
"time_range": 0' r! N2 k* A" w; S R
}
对应源代码的请求对象如下:4 \: n( v) ~% P% R
// BuildRequest is main struct when building transactions
type BuildRequest struct {
Tx *types.TxData `json:"base_transaction"`
Actions []map[string]interface{} `json:"actions"`
TTL json.Duration `json:"ttl"`
TimeRange uint64 `json:"time_range"`* W4 @) l* l) k2 B5 }3 i4 i: K& o% ]
}0 G" z; K" t) O3 k) Q
结构字段说明如下:: _" j. }; Q5 _& | y# m
Tx 交易的TxData部分,该字段为预留字段,为空即可$ `7 H6 b6 _$ d7 Z
TTL 构建交易的生存时间(单位为毫秒),意味着在该时间范围内,已经缓存的utxo不能用于再一次build交易,除非剩余的utxo足以构建一笔新的交易,否则会报错。当ttl为0时会被默认设置为600s,即5分钟5 o5 ^) O2 |$ j9 i" R
TimeRange 时间戳,意味着该交易将在该时间戳(区块高度)之后不会被提交上链,为了防止交易在网络中传输延迟而等待太久时间,如果交易没有在特定的时间范围内被打包,该交易便会自动失效
Actions 交易的actions结构,所有的交易都是由action构成的,map类型的interface{}保证了action类型的可扩展性。其中action中必须包含type字段,用于区分不同的action类型,action主要包含input和output两种类型,其详细介绍如下:- O0 N5 j% N2 n( X- {
input action 类型:
issue 发行资产
spend_account 以账户的模式花费utxo
spend_account_unspent_output 直接花费指定的utxo7 ?' M/ r6 j3 L9 j
output action 类型:8 t5 F( S% F3 ]- N
control_address 接收方式为地址模式
control_program 接收方式为(program)合约模式: [7 G9 ]) n2 v, [/ \# H8 Y
retire 销毁资产
s# x3 Q4 T! Q* o
注意事项:- @, W( c$ d" z8 v
一个交易必须至少包含一个input和output(coinbase交易除外,因为coinbase交易是由系统产生,故不在此加以描述),否则交易将会报错。
除了BTM资产(所有交易都是以BTM资产作为手续费)之外,其他资产在构建input和output时,所有输入和输出的资产总和必须相等,否则交易会报出输入输出不平衡的错误信息。1 b+ x5 I' w- ^8 |
交易的手续费: 所有inputs的BTM资产数量 - 所有outputs的BTM资产数量
交易中的资产amount都是neu为单位的,BTM的单位换算如下:1 BTM = 1000 mBTM = 100000000 neu! _- r0 b1 J7 x
0 \: H: i$ w, e* }% h
action简介
下面对构建交易时用到的各种action类型进行详细说明:; H$ n/ D1 e' \' W- R! [( Q( F, ~# l
issue
issueAction结构体源代码如下:% v/ w3 i$ ?& S
type issueAction struct {
assets *Registry* z" v; G& p6 h7 M% e' n" z6 I
bc.AssetAmount5 F0 N5 S# l+ P! e4 e
}
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"`
}
结构字段说明如下:
assets 主要用于资产的管理,无需用户设置参数( ~, I7 ]" d6 m, s4 Y% u7 x
AssetAmount 表示用户需要发行的资产ID和对应的资产数目,这里的AssetID需要通过create-asset创建,并且这里不能使用BTM的资产ID
. a+ o8 m$ v8 x
issueAction的json格式为:3 [2 ~- [, F+ ^: s
{
"amount": 100000000,
"asset_id": "3152a15da72be51b330e1c0f8e1c0db669269809da4f16443ff266e07cc43680",$ \2 ~$ R/ x2 x+ t' _' P; f
"type": "issue"* @/ D& ~/ P' D8 u" [
}5 Y5 y0 i" L& h2 b- d9 K$ o
例如发行一笔资产的交易示例如下:0 _/ A1 |$ K# | N+ u
(该交易表示发行数量为900000000个assetID的42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f的资产到接收地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费为20000000neu的BTM资产), |+ T) d% E5 T, X8 Q
{
"base_transaction": null,$ G# H6 ~/ x% H" d; r: r
"actions": [3 ~, r% b( I3 `
{1 V. C; Y$ [: r, ]: ^9 W' O1 }/ a
"account_id": "0ER7MEFGG0A02",. r: K; p2 H) N! u* `/ |
"amount": 20000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",3 e, G+ ]6 R1 I( O; h& z+ ^
"type": "spend_account"
},' J [' Y, p- L8 [! H) }* T" b
{
"amount": 900000000,
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f",& p2 }3 z; m* _
"type": "issue"7 b# h y( K/ l
},( S3 q6 q, i X) T4 s. E
{- a s1 j/ ?9 `: R. c6 M: Q8 w
"amount": 900000000,
"asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f",1 d# q/ v+ P+ [2 z% @% r
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",
"type": "control_address"
}+ O6 E. d. l7 b! G1 b! t
], M5 I1 s/ k, W
"ttl": 0,
"time_range": 0' @- U9 _! b+ F6 K# \* O6 p
}! O f" |6 L/ l) `/ l
spend_account
spendAction结构体源代码如下:8 @' d2 z/ b# R0 }9 W
type spendAction struct {0 P$ U9 W3 Z1 b8 A% `6 z
accounts *Manager* R5 m3 u: [ \* N1 V7 j
bc.AssetAmount" ]. c9 r7 Y( d' s. M& R, D* ]
AccountID string `json:"account_id"`
ClientToken *string `json:"client_token"`
}
type AssetAmount struct {5 D- z8 a! O+ M0 V
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"`- ?3 x7 n) h8 o6 U
}
结构字段说明如下:
accounts 主要用于账户的管理,无需用户设置参数# U7 }' J4 q, M7 `/ `3 z
AccountID 表示需要花费资产的账户ID6 B$ P" ]& _/ O4 [
AssetAmount 表示花费的资产ID和对应的资产数目
ClientToken 表示Reserve用户UTXO的限制条件,目前不填或为空即可) g; P4 L7 b4 E
spendAction的json格式为:% V' E9 L) z. z
{
"account_id": "0BF63M2U00A04",
"amount": 2000000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"type": "spend_account"
}
例如转账一笔资产的交易示例如下:6 ~6 w! p6 e. f+ J- ~! I$ H
(该交易表示通过账户的方式转账100000000neu的BTM资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费20000000neu = 输入BTM资产数量 - 输出BTM资产数量)' ], n$ g* E3 K0 A o% q" o* V9 `
{# p0 c8 X: E6 {! `, S! d0 T' i
"base_transaction": null,2 v3 t" \5 _# \) ^, u
"actions": [
{
"account_id": "0ER7MEFGG0A02",
"amount": 120000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",2 O, f8 _% `; J
"type": "spend_account"3 x. s2 v9 C1 @+ @2 O7 m
},
{ g4 j6 I8 k7 T) G U% }
"amount": 100000000,9 M' o$ [& a! c6 A) [" A9 x! P% V: p
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",2 z. s% e) z$ [, W8 ?4 F6 y
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",
"type": "control_address"5 ]' x4 h' ]8 H) B+ b; o: O2 ?
}# E6 R# z. w7 P" @0 ^" q5 i2 l6 u
],) R: Q6 P: A8 o r% z$ c
"ttl": 0,! P( Z4 s; x/ K& a2 A: c- v4 B1 f1 X; Z
"time_range": 0
}
$ J# N2 W- B) q1 \
spend_account_unspent_output8 D( H. Q1 \8 D. |. l
spendUTXOAction结构体源代码如下:
type spendUTXOAction struct {
accounts *Manager$ ~" Y% |- y% F, d7 e5 `8 c
OutputID *bc.Hash `json:"output_id"`
ClientToken *string `json:"client_token"`
}
结构字段说明如下:; k1 t) J# M$ z
accounts 主要用于账户的管理,无需用户设置参数
OutputID 表示需要花费的UTXO的ID,可以根据list-unspent-outputs查询可用的UTXO,其中OutputID对应该API返回结果的id字段8 }) `, i" v+ k. h
ClientToken 表示Reserve用户UTXO的限制条件,目前不填或为空即可6 D! _4 r/ E' Z5 P; s/ F2 x% d' D
2 J8 ]1 Q5 K, e* k1 E$ f: ^
spendUTXOAction的json格式为:
{1 Q4 _/ Y8 c; D/ ~& h
"type": "spend_account_unspent_output",8 i- @) \! z3 F7 u7 z# \3 U; p
"output_id": "58f29f0f85f7bd2a91088bcbe536dee41cd0642dfb1480d3a88589bdbfd642d9"
}9 S* {+ ] u, R2 H1 v# E/ l J
例如通过花费UTXO的方式转账一笔资产的交易示例如下:+ u3 g, C6 r, b) u1 o' F0 D
(该交易表示通过直接花费UTXO的方式转账100000000neu的BTM资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费 = 输入BTM资产的UTXO值 - 输出BTM资产数量)
{7 C0 E4 ?, O. o) H
"base_transaction": null,
"actions": [9 v, u% }& W7 r3 }/ Y
{; T/ L( ]( _. w% a1 E/ f6 |
"output_id": "58f29f0f85f7bd2a91088bcbe536dee41cd0642dfb1480d3a88589bdbfd642d9",
"type": "spend_account_unspent_output"2 u4 c' x6 y* i3 ~' P1 a& g
},
{
"amount": 100000000, g4 O# L8 T$ S- j+ i1 }' W. L1 L
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",! F7 R6 \; F1 O9 a
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",
"type": "control_address"
}/ j# |7 A# w+ c; ~6 X
],$ J7 [" i9 R% \8 B( E; ?9 m
"ttl": 0,& x# e2 {( W# v" m& }0 X- \
"time_range": 0
}
6 ~, o& q" d9 T, L, L' S
control_address! c5 l6 f' p- M3 Z. v$ S, b
controlAddressAction结构体源代码如下:& ]4 B3 Y! ]- j3 I7 f& `( `6 ^
type controlAddressAction struct {
bc.AssetAmount
Address string `json:"address"`! [3 T+ H8 L' M" ?. ]$ O
}
type AssetAmount struct {' ?8 B1 }+ T, o# l
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"`
}% u4 H- u3 O$ k1 a* J9 i0 t
结构字段说明如下:: j2 z' I2 ~3 ^5 ~3 N0 i Y% A
Address 表示接收资产的地址,可以根据 create-account-receiver API接口创建地址4 L/ n- Y4 J8 X
AssetAmount 表示接收的资产ID和对应的资产数目
$ d* t! l' U( c% ], e+ {1 I
controlAddressAction的json格式为:. t+ c+ @) P1 f' ^9 B ~ X0 O
{
"amount": 100000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",# c4 ]) X U4 F4 s) D1 Z9 |# ]
"address": "bm1q50u3z8empm5ke0g3ngl2t3sqtr6sd7cepd3z68",3 N/ S8 ]$ B5 C9 Y7 ?
"type": "control_address"
}
例如转账一笔资产的交易示例如下:2 @ w7 h0 Y5 w6 I" k/ K3 i5 k
(该交易表示通过账户的方式转账100000000neu的BTM资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中control_address类型表示以地址作为接收方式), t! T" {* W( L$ }5 K. u
{7 j7 X+ W, j) t! {# \
"base_transaction": null,( Z, y) Z& H/ W" ~
"actions": [
{0 j# v N2 Z/ m4 `3 t( I% I
"account_id": "0ER7MEFGG0A02",
"amount": 120000000,7 ^) F3 |" j" Z: h& l1 X
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",% W8 k. H" r+ O% Z; Y' Y
"type": "spend_account"
},
{
"amount": 100000000,( w- |* S# ^/ H* E) T- u
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",/ J/ X- w8 e( q* h) x
"address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me",/ J: W, ]/ B% k
"type": "control_address"
}" o; D# z) H5 y0 R
],
"ttl": 0,3 ^, q+ l1 u, |3 X/ Y
"time_range": 0
}* b" [* Z+ }0 c4 F
* J T6 I1 S5 O+ R9 @
control_program- @* c$ ^3 ]. v& ^% ~) s# K
controlProgramAction结构体源代码如下:
type controlProgramAction struct {
bc.AssetAmount
Program json.HexBytes `json:"control_program"`
}/ a8 [/ h" u& w5 r, P" Y
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"`1 o7 |) k# g0 j9 C2 W
}
结构字段说明如下:
Program 表示接收资产的合约脚本,可以根据 create-account-receiver API接口创建接收program(返回结果的 program 和 address 是一一对应的)
AssetAmount 表示接收的资产ID和对应的资产数目# J/ q. W" x R( x6 @' G) K
controlProgramAction的json格式为:
{
"amount": 100000000,) Y, F3 X0 H; I0 {
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",9 s5 T& G; p2 R: t% U
"control_program":"0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19",
"type": "control_program"5 E* ]6 M( \# w
}
例如转账一笔资产的交易示例如下:9 ?; X: P$ t/ T, F6 I; |* b: j
(该交易表示通过账户的方式转账100000000neu的BTM资产到接收program(跟address是一一对应的)0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19中, 其中control_program类型表示以program作为接收方式)4 X/ k) y: l8 V( G* e n' p. Q
{
"base_transaction": null,
"actions": [! x4 z0 G7 |+ o J! z# u
{
"account_id": "0ER7MEFGG0A02",
"amount": 120000000,, ?7 w% S# j. M& _9 c% o% `) g% ]
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"type": "spend_account"
},
{- y6 ^, s, Y& V' e3 k5 q7 X( q
"amount": 100000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",8 r- ?( q2 V" a Q) D% K: y( t4 ^
"control_program": "0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19", D. \, k" v' m
"type": "control_program"
}
],
"ttl": 0,5 ~7 a1 A3 @# B# o% s
"time_range": 0
}! b( T q2 \; W# m+ k
# b' z! R: }( x$ m4 l L1 I
retire
retireAction结构体源代码如下:
type retireAction struct {
bc.AssetAmount4 T9 j6 g- J% G* Q
}4 x4 s) c* X( ?: j: P: m4 D$ f
type AssetAmount struct {/ A) J; ^; e" N8 j% W, P
AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"`6 o: c+ R0 w2 k: ?# w7 X
Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"`
} T }- v" _* U1 f$ ^; k3 d
结构字段说明如下:
AssetAmount 表示销毁的资产ID和对应的资产数目
! x" p; S4 p; j' q) f6 l
retireAction的json格式为:
{, j3 @; T+ }2 ?( F% T
"amount": 900000000,
"asset_id": "3152a15da72be51b330e1c0f8e1c0db669269809da4f16443ff266e07cc43680",
"type": "retire"
}% Y- l! ?+ _, ]* t
例如销毁一笔资产的交易示例如下:
(该交易表示通过账户的方式将100000000neu的BTM资产销毁, retire表示销毁指定数量的资产)4 v) I& N: o; M1 z. L, {. Q
{
"base_transaction": null,: h/ \2 V7 f7 q8 x& C U5 ?
"actions": [
{3 m6 e0 X6 t* J
"account_id": "0ER7MEFGG0A02",* |4 v, Y% U) i2 G
"amount": 120000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",: u( b/ e2 L( K" I0 w( Q
"type": "spend_account"# b. v X6 `: ^! D0 ^4 r
}, [2 J; @# b( T4 i. f3 S2 o
{
"amount": 100000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",! i: M- X5 o n# z' s9 g l
"type": "retire"+ P0 A* ]2 @% }4 A3 U, l
}* a: b5 D1 L. T! L& v
],+ V" Y( i6 G7 o" K( n9 Z% K
"ttl": 0,
"time_range": 0& J$ M) G5 f z) f7 I& m" p6 f8 `: h
}2 X3 n9 P+ k/ a
build-transaction的输入构造完成之后,便可以通过http的调用方式进行发送交易,构建交易请求成功之后返回的json结果如下:
{& M" c5 W. j% E! j
"allow_additional_actions": false,1 J' @3 H) d6 M, f/ a! p9 S
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a077301000161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf456010003013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100",8 }- W8 \% L) _: s
"signing_instructions": [# g! k2 {4 l! D' `% w, @- a' {
{' c7 r' } e: }/ ?9 a; M
"position": 0,
"witness_components": [) H) ]$ V5 W7 `% j, I
{
"keys": [: \1 q) z* }) l' P. A
{4 b4 P2 x- D8 _
"derivation_path": [* F4 o6 }, R4 `" u7 V# O; f
"010100000000000000",
"0100000000000000"" X8 [, W, s0 I" Q; u
],6 M% `/ g2 L& Y) U( e0 X8 X
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}
],, h( d+ s( O/ C$ b
"quorum": 1,
"signatures": null,) k) q7 f2 y/ z' v
"type": "raw_tx_signature"
},
{, \- k3 R$ |4 c
"type": "data",, b, a c. q$ a" i* ^4 T% Y
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"
}5 T& |% b' x* I
]! A" o$ B- ?0 n# B$ ^
},
{( R! i* Z6 y: U, ^! l4 Z$ T& i
"position": 1,$ D) R @3 U$ k9 D7 Q# c
"witness_components": [" G- I( o4 X( h2 [6 r- w
{
"keys": [5 Z! N/ M3 i0 S3 R5 P* d& v
{' Z) k8 {7 w& w4 O# ~9 x( z
"derivation_path": [
"010100000000000000",
"0800000000000000"
],3 f3 F# U9 W9 d7 _
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"* Z& G' r0 N1 B6 U
}
],
"quorum": 1,
"signatures": null,1 \ j1 h% d4 r$ R
"type": "raw_tx_signature"
},4 q* q* w7 ?2 y7 v- G( S2 B
{+ J% }8 A# d8 i$ n- K" c
"type": "data",0 q# e# [7 _& y) `+ e% N% L
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419"( s" W+ M" x" {9 { C& r, ]
}$ O8 \2 ? }$ a) z X5 _
]+ c% K! o. j/ F' y5 a8 D2 W6 m: i
}
]
}2 H1 z( D6 q- z$ I
对应响应对象的源代码如下:! Q) e y9 S3 H
// Template represents a partially- or fully-signed transaction.' @) X/ K6 L6 [* O
type Template struct {+ M, J. ~: k' W* y
Transaction *types.Tx `json:"raw_transaction"`/ E' B- x9 S0 z# k& Y0 N
SigningInstructions []*SigningInstruction `json:"signing_instructions"`
// AllowAdditional affects whether Sign commits to the tx sighash or! n: s8 l3 x/ O2 P* A
// to individual details of the tx so far. When true, signatures' X# a- p8 A% _! v# z7 `
// commit to tx details, and new details may be added but existing- K- D# O# F' V* W
// ones cannot be changed. When false, signatures commit to the tx7 a! K- x. S/ ?7 O* K& v( I
// as a whole, and any change to the tx invalidates the signature.8 b6 s9 ]8 C% C" `. k
AllowAdditional bool `json:"allow_additional_actions"`* }: Z# g! c0 T/ m! Y3 T& z
}
结构字段说明如下:
Transaction 交易相关信息,该字段包含TxData和bc.Tx两个部分:
TxData 表示给用户展示的交易数据部分,该部分对用户可见( C8 |/ k5 d' R" ^7 W- v- U7 j
Version 交易版本& [+ b, g! W. E( P1 Y% T0 f# R6 K: o
SerializedSize 交易序列化之后的size. T0 m. a0 Y, P2 [ t( s
TimeRange 交易提交上链的最大时间戳(区块高度)(主链区块高度到达该时间戳(区块高度)之后,如果交易没有被提交上链,该交易便会失效). {4 c5 E# Y4 X8 x& S
Inputs 交易输入
Outputs 交易输出
bc.Tx 表示系统中处理交易用到的转换结构,该部分对用户不可见,故不做详细描述3 [; s# `$ P# {( q
SigningInstructions 交易的签名信息" x5 M' t7 e; f
Position 对input action签名的位置+ K! y% l+ K; k' F
WitnessComponents 对input action签名需要的数据信息,其中build交易的signatures为null,表示没有签名; 如果交易签名成功,则该字段会存在签名信息。该字段是一个interface接口,主要包含3种不同的类型:
SignatureWitness 对交易模板Template中交易input action位置的合约program进行哈希,然后对hash值进行签名
signatures (数组类型)交易的签名,sign-transaction执行完成之后才会有值存在
keys (数组类型)包含主公钥xpub和派生路径derivation_path,通过它们可以在签名阶段找到对应的派生私钥child_xprv,然后使用派生私钥进行签名
quorum 账户key 的个数,必须和上面的keys的长度相等。如果quorum 等于1,则表示单签账户,否则为多签账户4 O; r1 J( Y8 \9 _9 J9 h Q/ I
program 签名的数据部分,program的hash值作为签名数据。如果program为空,则会根据当前交易ID和对应action位置的InputID两部分生成一个hash,然后把它们作为指令数据自动构造一个program: @: N; U K3 v8 r8 Y" n
RawTxSigWitness 对交易模板Template的交易ID和对应input action位置的InputID(该字段位于bc.Tx中)进行哈希,然后对hash值进行签名/ T: ?" K ]7 M/ H; H( V6 y' w2 c
signatures (数组类型)交易的签名,sign-transaction执行完成之后才会有值存在( A* W0 `1 P- a
keys (数组类型)包含主公钥xpub和派生路径derivation_path,通过它们可以在签名阶段找到对应的派生私钥child_xprv,然后使用派生私钥进行签名1 q' E; v, x% H: J; e
quorum 账户key的个数,必须和上面的keys 的长度相等。如果quorum 等于1,则表示单签账户,否则为多签账户
DataWitness 该类型无需签名,验证合约program的附加数据
AllowAdditional 是否允许交易的附加数据,如果为true,则交易的附加数据会添加到交易中,但是不会影响交易的执行的program脚本,对签名结果不会造成影响; 如果为false,则整个交易作为一个整体进行签名,任何数据的改变将影响整个交易的签名6 n1 n$ i; K& p
估算手续费" [& p* u" W0 g# Z
估算手续费接口estimate-transaction-gas是对build-transaction的结果进行手续费的预估,估算的结果需要重新加到build-transaction的结果中,然后对交易进行签名和提交。其主要流程如下:
build - estimate - build - sign - submit* N) Q" [% V4 S8 S; _" s
估算手续费的输入请求json格式如下:' \# v( ]4 Z) J3 Q1 Q
{
"transaction_template": { ~% p6 J( R1 J
"allow_additional_actions": false,8 n# i2 `! t0 p+ S w
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a077301000161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf456010003013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100",) h. |7 m( D) C: c0 z5 U
"signing_instructions": [+ v& c& B% p' z7 ^1 I
{
"position": 0,: i; V% h- ^& p/ |2 P, v( u8 L
"witness_components": [
{
"keys": [
{
"derivation_path": [# W( u$ p" r3 R+ Y* K
"010100000000000000",
"0100000000000000"" v1 R3 l: d4 h9 X' M; T8 T+ `* f
],
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}) J6 x) M, U( A9 L
],
"quorum": 1,
"signatures": null,
"type": "raw_tx_signature"
},( M. q) E& Y3 }& |
{% X6 U. s# E0 h% [8 X0 P
"type": "data"," k' v5 [$ \6 f- X9 f! ^5 l
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"
} G/ D% b8 ^6 }) ]
]
},0 h# Z2 z8 z4 _8 v% O$ E
{( g) d1 ~* f. z" |5 D
"position": 1,
"witness_components": [/ \% t$ o* a: @. Y
{' y3 s5 F; j3 q% F
"keys": [- V2 q' c7 o) H7 f3 S# ?1 l1 `2 Y
{
"derivation_path": [% i1 M- n2 j0 i8 ]0 J/ G2 Y
"010100000000000000",
"0800000000000000"
], a# U* C5 J; u) h/ Y3 ^
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}1 N5 I3 G4 D5 o3 l
],5 k0 Z( ]* W8 F5 y
"quorum": 1,
"signatures": null,6 b2 N( S% @+ e' Z" C
"type": "raw_tx_signature". v& q+ l3 `+ ]0 G# I& L" t0 ]
},: ~7 e5 w, M5 T
{
"type": "data",% D5 x# C# d2 c! }0 r6 Z3 K
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419"3 ?/ i$ f9 d2 x3 k! o
}3 ?' l# [7 @" ~8 m* Y; [; v4 |
]( x/ e3 s1 e# m6 v. q4 G
}. f! H4 y4 I1 ?
]2 F; _& x/ E2 {1 B
}
}
对应响应对象的源代码如下:
type request struct{2 M1 d8 A# `9 I) N5 Z
TxTemplate txbuilder.Template `json:"transaction_template"`
}; A8 q6 j$ L- X. H' r; |9 D' _8 y+ v
// Template represents a partially- or fully-signed transaction.+ ^: B a8 t+ J0 W; d7 k$ H
type Template struct {, V1 V, s- l2 {/ N
Transaction *types.Tx `json:"raw_transaction"`
SigningInstructions []*SigningInstruction `json:"signing_instructions"`
// AllowAdditional affects whether Sign commits to the tx sighash or0 r9 ~5 D1 Q. B% F5 M) K
// to individual details of the tx so far. When true, signatures' c" S+ W$ Q8 d# d5 N7 R
// commit to tx details, and new details may be added but existing
// ones cannot be changed. When false, signatures commit to the tx
// as a whole, and any change to the tx invalidates the signature.8 E% P, D3 @& _3 P; G) `, d6 l
AllowAdditional bool `json:"allow_additional_actions"`
}
其中TxTemplate相关字段的说明见build-transaction的结果描述3 g0 b+ q* ]$ j+ P9 b; v. }: @
调用estimate-transaction-gas接口成功之后返回的json结果如下:+ n" Y/ F/ D+ x* W# S
{) I+ A9 i8 e1 J0 \
"total_neu": 5000000,) H0 Y% O: k7 f0 v
"storage_neu": 3840000,* ^' y# Q5 V d z. ]* n/ b
"vm_neu": 14190002 ~, w3 U- S6 I# R
}4 J6 m* E1 N' ^7 X3 v
对应响应对象的源代码如下:9 _" g6 H. Y$ @
// EstimateTxGasResp estimate transaction consumed gas
type EstimateTxGasResp struct {
TotalNeu int64 `json:"total_neu"`
StorageNeu int64 `json:"storage_neu"`. G) m9 |5 n, Z7 `& L* M( C6 J
VMNeu int64 `json:"vm_neu"`1 w9 d8 E3 d- N2 k/ R, p+ }
}
结构字段说明如下:% V p' m+ ?9 g- X, N6 T9 }
TotalNeu 预估的总手续费(单位为neu),该值直接加到build-transaction的BTM资产输入action中即可
StorageNeu 存储交易的手续费
VMNeu 运行虚拟机的手续费
2、签名交易
API接口 sign-transaction,代码api/hsm.go#L53
签名交易的输入请求json格式如下:: G& C9 \( s3 a. |
{9 w/ M3 G$ m' I# V( A6 p9 f
"password": "123456",
"transaction": {; j9 `7 O0 ~* S; x) N: M B7 m$ k
"allow_additional_actions": false,2 f9 H7 y& `2 Z0 Y
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a077301000161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf456010003013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100",& r: m6 h( n1 M% a
"signing_instructions": [. y' w! q& a; ?8 v
{5 I- T( Z6 A, S8 }) B3 S0 g8 A
"position": 0,
"witness_components": [
{, o7 f0 D1 C0 p0 e+ x
"keys": [ {% F, }4 X$ E% a# w ]
{
"derivation_path": [
"010100000000000000",
"0100000000000000"
],
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"! j8 @. u2 k/ J
}
],
"quorum": 1,1 a2 B5 H' E* ~
"signatures": null,1 r+ f+ r" S+ }& L) l: U6 @
"type": "raw_tx_signature"
},; I( C9 U8 G/ u2 m3 {
{& M4 x. N6 y6 q: _
"type": "data",1 E+ h/ J, o) M" F1 a: D
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"
}$ H9 a, s5 p5 T+ t8 q
]
},
{" n7 t7 ?* o9 x
"position": 1,! O; K; y3 w0 \! h3 ]' Q
"witness_components": [
{% b2 Y0 v8 ^$ a V \3 h
"keys": [
{5 G5 Z( H/ _3 i. n% ~
"derivation_path": [ |( m+ W4 J. O3 G( N0 h
"010100000000000000",
"0800000000000000"' u! J- j( d$ f# Z
],* L4 U, i8 p3 o! N: `
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}- |6 [ o& s: C# [! K3 i% w
],% p7 V. p4 T7 ?, C2 i# {
"quorum": 1,5 y V; S$ t1 z/ |
"signatures": null,* X9 D" ?+ t' f. \( x! L1 z
"type": "raw_tx_signature"; i/ l- W0 V `' H4 l, c9 I. }* k
},
{
"type": "data",
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419": p8 J. E' I6 P- z" U
}
]) m. Y" }6 g/ P- }2 \
}1 f3 a! N* R; B
]
}! ^: z& b' \+ X0 d# z5 q
}
对应请求对象的源代码如下:
type SignRequest struct { //function pseudohsmSignTemplates request
Password string `json:"password"`
Txs txbuilder.Template `json:"transaction"`! u' l0 Y# r5 M4 e
}6 t7 e' D& q$ l* A: v* _; d7 F
结构字段说明如下:
Password 签名的密码,根据密码可以从节点服务器上解析出用户的私钥,然后用私钥对交易进行签名
Txs 交易模板,build-transaction的返回结果,结构类型为 txbuilder.Template,相关字段的说明见build-transaction的结果描述1 j4 v$ I7 l; r; o& g
% |" Z* {( \! }9 j/ M; W! X( O1 f- s
签名交易sign-transaction请求成功之后返回的json结果如下:* d( G! w* l2 r. t; H# \ Z
{$ L# A [2 s% }' x! k
"sign_complete": true,. q8 u1 S0 s. p( l, D: b# S% w+ P0 u
"transaction": {, X I, p, p6 \; u( k9 k$ s
"allow_additional_actions": false,9 y( j& ]5 j2 [4 g8 n
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a0773630240273d5fc4fb06909fbc2968ea91c411fd20f690c88e74284ce2732052400129948538562fe432afd6cf17e590e8645b80edf80b9d9581d0a980d5f9f859e3880620d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd50161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf4566302400cf0beefceaf9fbf1efadedeff7aee5b38ee7a25a20d78b630b01613bc2f8c9230555a6e09aaa11a82ba68c0fc9e98a47c852dfe3de851d93f9b2b7ce256f90d2005cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe6154053541903013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100",
"signing_instructions": [
{
"position": 0,
"witness_components": [" R( M- w0 d' t+ y/ j
{# a' ]; g6 X, m) h+ s
"keys": [+ s" [0 I! j& @5 e3 _) x3 f
{
"derivation_path": [
"010100000000000000",/ ?( X2 w- X- C7 n
"0100000000000000") H* w. e# h& m9 o6 A: ?- m; d- V3 d
],, Q5 t2 x) J, f* o2 b& Q# R
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"
}
],
"quorum": 1,
"signatures": [
"273d5fc4fb06909fbc2968ea91c411fd20f690c88e74284ce2732052400129948538562fe432afd6cf17e590e8645b80edf80b9d9581d0a980d5f9f859e38806"
],
"type": "raw_tx_signature"" M+ Q7 c' j F: ~
},
{9 E+ ?0 |* t' M0 A" [& @! e7 {
"type": "data",; c$ i, G% }/ Y- Q2 C
"value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5"
}
]
},: ?/ O6 c- {) ~; ~
{+ S. U+ ~4 ^/ h
"position": 1,
"witness_components": [6 k; B- a: E3 I2 D
{% A: e6 t s+ C9 c+ P* e( |* Q
"keys": [
{
"derivation_path": [
"010100000000000000",; j7 ^& V; y, u) _" ?- T
"0800000000000000"8 X$ `3 q' [* g, H) E, G$ p
],/ Y: J2 }1 o9 k: O1 ~
"xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8"6 V2 N# z- G! c
}
],
"quorum": 1,
"signatures": [
"0cf0beefceaf9fbf1efadedeff7aee5b38ee7a25a20d78b630b01613bc2f8c9230555a6e09aaa11a82ba68c0fc9e98a47c852dfe3de851d93f9b2b7ce256f90d"
],% q$ F, ~5 j h, ~8 R7 K
"type": "raw_tx_signature"8 i' ?+ f' g/ K! t" b8 e& O
},
{
"type": "data",, M+ `' ]: U/ I0 v
"value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419"6 }( }) b0 z2 ]2 g3 P/ Q$ Y& n
}* R' g4 F8 Q- l+ f1 Z
]
}9 ~7 Z B3 F9 l3 w
] B2 Z0 q1 R) q6 ?: F8 ~" o
}
}# d+ [+ D# I4 y" ]7 M. u$ }
对应响应对象的源代码如下:7 _* y; q' L1 E" r" g
type signResp struct {
Tx *txbuilder.Template `json:"transaction"`" Q: C! p1 R: K* S# f; d
SignComplete bool `json:"sign_complete"`1 x5 ~( |4 p7 `
}
结构字段说明如下:0 a5 ^& S A( M" ]
Tx 签名之后的交易模板txbuilder.Template,如果签名成功则signatures会由null变成签名的值,而raw_transaction的长度会变长,是因为bc.Tx部分添加了验证签名的参数信息3 \- @4 j, p0 c+ ^: y
SignComplete 签名是否完成标志,如果为true表示签名完成,否则为false表示签名未完成,单签的话一般可能为签名密码错误; 而多签的话一般为还需要其他签名。签名失败只需将签名的交易数据用正确的密码重新签名即可,无需再次build-transaction构建交易+ c2 x4 L" t6 D- K- [
3 S7 V% y: s. D9 r# h
3、提交交易" N) Z# J$ Q; p
API接口 submit-transaction,代码api/transact.go#L1351 \! `5 \- G" f" v/ f0 e3 a( r4 x
提交交易的输入请求json格式如下:0 m# ~& F- |1 P2 X, s9 I: n
{
"raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a0773630240273d5fc4fb06909fbc2968ea91c411fd20f690c88e74284ce2732052400129948538562fe432afd6cf17e590e8645b80edf80b9d9581d0a980d5f9f859e3880620d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd50161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf4566302400cf0beefceaf9fbf1efadedeff7aee5b38ee7a25a20d78b630b01613bc2f8c9230555a6e09aaa11a82ba68c0fc9e98a47c852dfe3de851d93f9b2b7ce256f90d2005cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe6154053541903013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100"+ p+ u8 l! A6 b) F- g7 g
}
对应源代码的请求对象如下:! v# C: t1 w2 X: r! L
type SubmitRequest struct { //function submit request
Tx types.Tx `json:"raw_transaction"`: U* Y2 K4 `4 \! n- _3 o2 F
}; g5 C$ t5 w' s. m3 S6 o+ x e
结构字段说明如下:3 @8 E. w2 \0 @" a5 b! `- V7 s
Tx 签名完成之后的交易信息。这里需要注意该字段中的raw_transaction不是签名交易sign-transaction的全部返回结果,而是签名交易返回结果中transaction中的raw_transaction字段。
9 n ]. n8 c" }% D
submit-transaction请求成功之后返回的json结果如下:
{6 {. y0 ~. U! G
"tx_id": "2c0624a7d251c29d4d1ad14297c69919214e78d995affd57e73fbf84ece361cd"
}# U2 f# k* V0 R$ s8 N6 A
对应源代码的响应对象如下:
type submitTxResp struct {
TxID *bc.Hash `json:"tx_id"`9 u4 R3 F+ g( G. _7 ]* n
}& ]- H4 J0 J7 \( q3 b( m/ \
结构字段说明如下:6 F7 N$ @7 m1 L1 k: w) j/ D, r
TxID 交易ID,当交易被提交到交易池之后会显示该信息,否则表示交易失败
成为第一个吐槽的人