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