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