Github地址:https://github.com/Bytom/bytom% o# r0 d% o+ d8 l% D" ^8 I
Gitee地址:https://gitee.com/BytomBlockchain/bytom
tx_signer
Java implementation of signing transaction offline to bytomd.
Pre5 ]# R4 ~, \' S; _4 E
Get the source code
$ git clone https://github.com/Bytom/bytom.git $GOPATH/src/github.com/bytom
git checkout. R" n5 P/ F6 K* e% j) j" O. `
$ git checkout dev/ r5 y: |" s- G* y% N
Why need dev branch? Because you could call decode transaction api from dev branch and obtain tx_id and some inputs ids.
Build
$ cd $GOPATH/src/github.com/bytom
$ make bytomd # build bytomd
$ make bytomcli # build bytomcli- W4 v+ R5 m. A/ a& ~! U
When successfully building the project, the bytom and bytomcli binary should be present in cmd/bytomd and cmd/bytomcli directory, respectively.) N% b( l4 C, J. D; S3 G
Initialize
First of all, initialize the node:
$ cd ./cmd/bytomd+ y: L6 f. ]. W/ U* y( p, K8 k
$ ./bytomd init --chain_id solonet
launch
$ ./bytomd node --mining, }4 S% A8 v! o1 P( [9 P9 j
Usage
Build jar# S5 r+ } P: Y9 @& J$ d
first get source code! E* y/ p9 r$ p) N" r0 ]7 B4 J
git clone https://github.com/successli/tx_signer.git
get jar package( }, h. N, h' G+ C* u3 ~
$ mvn assembly:assembly -Dmaven.test.skip=true' _: R, W; I, R7 R
You can get a jar with dependencies, and you can use it in your project.( P, P, Y/ l1 v( {4 M d
3 R9 b0 B- P* ?& Q9 y* W+ G
Test cases E; Y3 g. v; U6 x4 U& F' ^
Need 3 Parameters:
Call method:
// return a Template object signed offline basically." w3 D2 j. C& G7 L2 Z
Template result = signatures.generateSignatures(privates, template, rawTransaction);
// use result's raw_transaction call sign transaction api to build another data but not need password or private key.6 L* f9 E" V0 ~2 f' |
Single-key Example:/ ]1 t- q# Z" u
@Test+ ^8 S+ c8 C, Y# q7 N6 ]
// 使用 SDK 来构造 Template 对象参数, 单签: R& V9 c6 I$ k& K5 |) P
public void testSignSingleKey() throws BytomException {
Client client = Client.generateClient();
String asset_id = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
String address = "sm1qvyus3s5d7jv782syuqe3qrh65fx23lgpzf33em";
// build transaction obtain a Template object, |; C# J- q3 G3 [. \! X7 A$ E
Template template = new Transaction.Builder()
.addAction(" f3 T! L- T8 U5 U
new Transaction.Action.SpendFromAccount()* j) r$ N& M2 s
.setAccountId("0G0NLBNU00A02")+ o4 \$ \, j2 A8 @
.setAssetId(asset_id)
.setAmount(40000000). l9 @! Y2 z0 a8 m+ ]( c
)
.addAction(& S' ?4 S8 G) P& r5 _: C3 H, J
new Transaction.Action.SpendFromAccount()9 i- J7 z. p+ p* e
.setAccountId("0G0NLBNU00A02")4 @9 p z1 |# b4 B* w+ F
.setAssetId(asset_id)
.setAmount(300000000)
)4 T; W* ~4 C" [; i1 k
.addAction(' v) e5 U8 b" T6 H& p$ G
new Transaction.Action.ControlWithAddress()# e. p' {+ Y d/ H8 k
.setAddress(address)6 `4 E u! h, ^% a
.setAssetId(asset_id)0 n6 e7 G1 \9 r8 f$ i
.setAmount(30000000)
).build(client);6 t6 D6 p- B( \
logger.info("template: " + template.toJson());
// use Template object's raw_transaction id to decode raw_transaction obtain a RawTransaction object
RawTransaction decodedTx = RawTransaction.decode(client, template.rawTransaction);
logger.info("decodeTx: " + decodedTx.toJson());
// need a private key array9 l( R$ m' b/ k
String[] privateKeys = new String[]{"10fdbc41a4d3b8e5a0f50dd3905c1660e7476d4db3dbd9454fa4347500a633531c487e8174ffc0cfa76c3be6833111a9b8cd94446e37a76ee18bb21a7d6ea66b"};
logger.info("private key:" + privateKeys[0]);
// call offline sign method to obtain a basic offline signed template
Signatures signatures = new SignaturesImpl();
Template basicSigned = signatures.generateSignatures(privateKeys, template, decodedTx);
logger.info("basic signed raw: " + basicSigned.toJson());& q: x, I/ `" u3 d. j
// call sign transaction api to calculate whole raw_transaction id
// sign password is None or another random String
Template result = new Transaction.SignerBuilder().sign(client,' w( z# k8 ?8 B' s6 R; _; C3 d
basicSigned, "");/ D* u/ C' @/ Y+ E( ~/ H
logger.info("result raw_transaction: " + result.toJson());, a& y$ F+ M: r# |( C7 H% [
// success to submit transaction
}# K, s" J3 J9 h! v/ a2 i
Multi-keys Example:2 d9 D! h U3 t' b9 D
G5 {7 Y% A& N7 f8 T+ ?6 I" x6 X
Need an account has two or more keys.) |. x3 ]' o% N% F3 n
@Test: o6 b: F5 p% k3 }0 H
// 使用 SDK 来构造 Template 对象参数, 多签0 u. Z0 x v9 Y s \/ R1 D
public void testSignMultiKeys() throws BytomException {
Client client = Client.generateClient();$ j6 L! z8 F- B/ S! B! ^. r
String asset_id = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";: ~$ k# s# @; Y9 ~
String address = "sm1qvyus3s5d7jv782syuqe3qrh65fx23lgpzf33em";' Z \& v3 K! R, b) m" H- _
// build transaction obtain a Template object
// account 0G1RPP6OG0A06 has two keys
Template template = new Transaction.Builder(), T0 U5 @. d1 m' g; q+ H
.setTtl(10)
.addAction(* v Z/ C) u% {8 p i! S) A
new Transaction.Action.SpendFromAccount()' w( h) P5 N' R+ K( a0 D, k
.setAccountId("0G1RPP6OG0A06")$ X) e3 f: g$ G4 Z A
.setAssetId(asset_id)
.setAmount(40000000)( ?+ N: p5 v& B) b9 ~; Z
)
.addAction(8 u) {) c1 ]1 F0 I; G, S& b2 o* Z
new Transaction.Action.SpendFromAccount()
.setAccountId("0G1RPP6OG0A06")) y" v9 Z7 |& @6 n* j T5 Q$ Y
.setAssetId(asset_id)
.setAmount(300000000)/ A# r! `( k7 x% @3 N" z" }0 f
)+ J e1 P* x1 Y8 H0 W
.addAction(! N3 t& y% @: w
new Transaction.Action.ControlWithAddress()0 k, R) Y0 Y$ f; W
.setAddress(address) I# s# J) {1 Y0 v! @
.setAssetId(asset_id)- Z' D4 p- e) H8 H, E
.setAmount(30000000)1 ~: X; |! m; C; w- l
).build(client);
logger.info("template: " + template.toJson());
// use Template object's raw_transaction id to decode raw_transaction obtain a RawTransaction object
RawTransaction decodedTx = RawTransaction.decode(client, template.rawTransaction);
logger.info("decodeTx: " + decodedTx.toJson());
// need a private key array0 ^0 \; J; g" x) q; q! G! P1 y
String[] privateKeys = new String[]{"08bdbd6c22856c5747c930f64d0e5d58ded17c4473910c6c0c3f94e485833a436247976253c8e29e961041ad8dfad9309744255364323163837cbef2483b4f67",! Z) B% [% L4 x! H7 v
"40c821f736f60805ad59b1fea158762fa6355e258601dfb49dda6f672092ae5adf072d5cab2ceaaa0d68dd3fe7fa04869d95afed8c20069f446a338576901e1b"};
logger.info("private key 1:" + privateKeys[0]);- z R8 Y) F/ H0 O5 Q0 |
logger.info("private key 2:" + privateKeys[1]);( |5 g- J2 W& C5 X
// call offline sign method to obtain a basic offline signed template
Signatures signatures = new SignaturesImpl();
Template basicSigned = signatures.generateSignatures(privateKeys, template, decodedTx);( b, C& I' G; O
logger.info("basic signed raw: " + basicSigned.toJson());4 Y0 l7 V3 P2 E& a% s* J
// call sign transaction api to calculate whole raw_transaction id
// sign password is None or another random String
Template result = new Transaction.SignerBuilder().sign(client,6 V# [' h" M: M! o8 @) s
basicSigned, "");9 @ G, f% C/ N: `9 s0 [/ P* H
logger.info("result raw_transaction: " + result.toJson());" b( j" n( j! F8 @6 I+ H
// success to submit transaction2 y, q+ ?+ u! t P2 S
}! u+ Z( U0 s( U# b# ]$ ]* v; y8 Z
Multi-keys and Multi-inputs Example:
@Test/ V% s& i/ _% ?) n) @
// 使用 SDK 来构造 Template 对象参数, 多签, 多输入
public void testSignMultiKeysMultiInputs() throws BytomException {
Client client = Client.generateClient();
String asset_id = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
String address = "sm1qvyus3s5d7jv782syuqe3qrh65fx23lgpzf33em";
// build transaction obtain a Template object6 Z" C" t0 v- n8 U$ x' e
Template template = new Transaction.Builder()
.setTtl(10)
// 1 input
.addAction(
new Transaction.Action.SpendFromAccount()
.setAccountId("0G1RPP6OG0A06") // Multi-keys account
.setAssetId(asset_id)
.setAmount(40000000)6 q$ a5 p, m* d' g Y5 f
)7 s1 C( b2 N6 k, ?' B. ]
.addAction(, v8 N& Y, E3 j& G, @/ D
new Transaction.Action.SpendFromAccount()
.setAccountId("0G1RPP6OG0A06")* d0 _$ E5 w3 L9 V* p
.setAssetId(asset_id)
.setAmount(300000000)0 J( P" M; t9 W! y6 j$ h
) // 2 input
.addAction(
new Transaction.Action.SpendFromAccount()4 g I! N. F4 `0 d
.setAccountId("0G1Q6V1P00A02") // Multi-keys account& W5 F5 |6 P8 d) u& E
.setAssetId(asset_id)
.setAmount(40000000)
)7 f6 L+ e3 ]. p
.addAction( B( n/ ^' w2 I; b
new Transaction.Action.SpendFromAccount()& g1 p) t. U+ w" k5 g, E
.setAccountId("0G1Q6V1P00A02")
.setAssetId(asset_id)
.setAmount(300000000)
)
.addAction(
new Transaction.Action.ControlWithAddress()
.setAddress(address)8 Z; a' o1 j6 S, Y/ e
.setAssetId(asset_id)0 }2 ]" l8 g3 m. w9 @7 b9 B
.setAmount(60000000)
).build(client);$ C) I) V: {( l& r2 W
logger.info("template: " + template.toJson());
// use Template object's raw_transaction id to decode raw_transaction obtain a RawTransaction object
RawTransaction decodedTx = RawTransaction.decode(client, template.rawTransaction);
logger.info("decodeTx: " + decodedTx.toJson());
// need a private key array6 R% ?6 h* J) u# {: Y! x
String[] privateKeys = new String[]{"08bdbd6c22856c5747c930f64d0e5d58ded17c4473910c6c0c3f94e485833a436247976253c8e29e961041ad8dfad9309744255364323163837cbef2483b4f67",# {0 s6 F" X% V, `
"40c821f736f60805ad59b1fea158762fa6355e258601dfb49dda6f672092ae5adf072d5cab2ceaaa0d68dd3fe7fa04869d95afed8c20069f446a338576901e1b",
"08bdbd6c22856c5747c930f64d0e5d58ded17c4473910c6c0c3f94e485833a436247976253c8e29e961041ad8dfad9309744255364323163837cbef2483b4f67"};9 h% k" R4 \9 Z" G) M" }* ]
logger.info("private key 1:" + privateKeys[0]);; c1 R- t' Y: S. ]8 B
logger.info("private key 2:" + privateKeys[1]);! m# v7 z; S; b9 U1 e- v
// call offline sign method to obtain a basic offline signed template; r# u; Y# S9 y2 a9 f
Signatures signatures = new SignaturesImpl();
Template basicSigned = signatures.generateSignatures(privateKeys, template, decodedTx);# ?' ?- Q8 i& G% ?6 O
logger.info("basic signed raw: " + basicSigned.toJson());
// call sign transaction api to calculate whole raw_transaction id
// sign password is None or another random String+ G& o/ l% f: O+ ?2 d" o# C
Template result = new Transaction.SignerBuilder().sign(client,
basicSigned, "");# X* A! G( m* E$ k; V
logger.info("result raw_transaction: " + result.toJson());
// success to submit transaction& ?& X; ^) H/ z3 N
}