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