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