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