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