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