Github地址:https://github.com/Bytom/bytom4 \' W9 D. n t8 D+ r
Gitee地址:https://gitee.com/BytomBlockchain/bytom
tx_signer
Java implementation of signing transaction offline to bytomd.
Pre+ {% A4 j; r4 K" Q
Get the source code
$ git clone https://github.com/Bytom/bytom.git $GOPATH/src/github.com/bytom! t/ o' ^; X3 A( k. F1 G
git checkout1 J( w) P: c2 [* F; R4 U
$ git checkout dev+ l3 t! }( K: H! q4 S) H! o
Why need dev branch? Because you could call decode transaction api from dev branch and obtain tx_id and some inputs ids.
Build: W; y& \7 K' @: \
$ cd $GOPATH/src/github.com/bytom& j0 Q2 q2 t) e! q6 ? K) z1 |+ V
$ make bytomd # build bytomd$ t* \, \0 w+ i8 d7 ]/ a
$ make bytomcli # build bytomcli0 A8 e' x3 P& T* M% t
When successfully building the project, the bytom and bytomcli binary should be present in cmd/bytomd and cmd/bytomcli directory, respectively.
Initialize
First of all, initialize the node:* f' ?& O* A8 e0 E$ R
$ cd ./cmd/bytomd) L, e8 v W' u$ ?0 i
$ ./bytomd init --chain_id solonet' X2 [2 y2 ?0 D
launch9 j% M x7 W, D9 ~2 L1 u7 ]* H
$ ./bytomd node --mining% i2 i/ g5 `: K$ ~/ q' Z" ~0 K% G
Usage9 A5 D* m. F( u" Y4 v/ ~
Build jar0 {' r. A3 g) S* [
first get source code
git clone https://github.com/successli/tx_signer.git1 m- D. m* q, n+ [7 A
get jar package- A3 z( }: z3 o
$ mvn assembly:assembly -Dmaven.test.skip=true P& Z' \. k7 p& Z8 }7 @
You can get a jar with dependencies, and you can use it in your project.& i1 O `$ j. b8 _
, B P# B" ^& ~7 g' E2 K% ]- M% Z
Test cases
Need 3 Parameters:
Call method:
// return a Template object signed offline basically. M* M) c3 ~( x2 X
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.3 C+ V) E/ T0 P# y
Single-key Example:# h2 w+ a! J6 `8 o; U+ N* W
@Test: |( _: Z! m( B% k O
// 使用 SDK 来构造 Template 对象参数, 单签
public void testSignSingleKey() throws BytomException {
Client client = Client.generateClient();9 _! _- }9 B) M
String asset_id = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";% ~9 Q4 k' I$ @' S
String address = "sm1qvyus3s5d7jv782syuqe3qrh65fx23lgpzf33em";
// build transaction obtain a Template object
Template template = new Transaction.Builder()
.addAction(
new Transaction.Action.SpendFromAccount()
.setAccountId("0G0NLBNU00A02")! M6 C- }* h% U" d" I8 F
.setAssetId(asset_id)
.setAmount(40000000)
)
.addAction(
new Transaction.Action.SpendFromAccount(), D8 H/ H! b0 j2 r
.setAccountId("0G0NLBNU00A02")
.setAssetId(asset_id). T6 E% u) o3 B2 Q9 g) p- ^
.setAmount(300000000)
)
.addAction(
new Transaction.Action.ControlWithAddress()0 y& f& z: Z* E h
.setAddress(address)* t B a* T% i/ E7 ~" H/ C
.setAssetId(asset_id)4 K% d3 E3 t# w" [, ]( l: i6 E
.setAmount(30000000)
).build(client);6 F0 r5 [, K( ^' w
logger.info("template: " + template.toJson());* D( D3 a/ k9 J( a6 H9 @
// use Template object's raw_transaction id to decode raw_transaction obtain a RawTransaction object! U. ~$ h) L" P$ ^1 {
RawTransaction decodedTx = RawTransaction.decode(client, template.rawTransaction);
logger.info("decodeTx: " + decodedTx.toJson());
// need a private key array0 j A9 ` N! t h0 N3 x
String[] privateKeys = new String[]{"10fdbc41a4d3b8e5a0f50dd3905c1660e7476d4db3dbd9454fa4347500a633531c487e8174ffc0cfa76c3be6833111a9b8cd94446e37a76ee18bb21a7d6ea66b"};
logger.info("private key:" + privateKeys[0]);7 h7 ]5 b; J: e+ w4 z% X
// call offline sign method to obtain a basic offline signed template
Signatures signatures = new SignaturesImpl();
Template basicSigned = signatures.generateSignatures(privateKeys, template, decodedTx);) w0 G$ [0 F- \$ ^
logger.info("basic signed raw: " + basicSigned.toJson());
// call sign transaction api to calculate whole raw_transaction id2 \, p/ n# I, c( O7 s
// sign password is None or another random String5 z; t$ v, d: T! J
Template result = new Transaction.SignerBuilder().sign(client,
basicSigned, "");8 }# }# b. Y+ b1 d
logger.info("result raw_transaction: " + result.toJson());
// success to submit transaction
}
Multi-keys Example:
Need an account has two or more keys.
@Test8 j4 l9 J; M& {) O* Z
// 使用 SDK 来构造 Template 对象参数, 多签) c. @" O I! g. Y! I0 n! `8 Z
public void testSignMultiKeys() throws BytomException {" J3 B7 g& Y: i' p
Client client = Client.generateClient();
String asset_id = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
String address = "sm1qvyus3s5d7jv782syuqe3qrh65fx23lgpzf33em";5 X. L3 X8 B7 j9 V
// build transaction obtain a Template object
// account 0G1RPP6OG0A06 has two keys! F) Q9 q- {) o: I8 L
Template template = new Transaction.Builder()
.setTtl(10)
.addAction(
new Transaction.Action.SpendFromAccount()
.setAccountId("0G1RPP6OG0A06")
.setAssetId(asset_id)
.setAmount(40000000)
)
.addAction(( y" t6 s! E. l' m8 V6 ]4 H
new Transaction.Action.SpendFromAccount(): r5 `& b8 e1 T% o
.setAccountId("0G1RPP6OG0A06")' F! D \5 o$ \6 H) a
.setAssetId(asset_id) O8 b* n6 _' @* H* Z
.setAmount(300000000)* l6 N8 G: h$ d$ }9 h( D
)
.addAction(
new Transaction.Action.ControlWithAddress()
.setAddress(address)! P: t7 w2 z$ \2 c2 o8 N8 ]( {
.setAssetId(asset_id)
.setAmount(30000000)' i0 h4 X, D) g! W' `
).build(client);
logger.info("template: " + template.toJson());/ l; U. `6 s* O' ^1 x1 P: y
// use Template object's raw_transaction id to decode raw_transaction obtain a RawTransaction object
RawTransaction decodedTx = RawTransaction.decode(client, template.rawTransaction);' H) P" L: P: T$ D
logger.info("decodeTx: " + decodedTx.toJson());4 k/ A% H; q$ t9 M) S
// need a private key array
String[] privateKeys = new String[]{"08bdbd6c22856c5747c930f64d0e5d58ded17c4473910c6c0c3f94e485833a436247976253c8e29e961041ad8dfad9309744255364323163837cbef2483b4f67",3 A; ?( d0 n. J; ~4 d
"40c821f736f60805ad59b1fea158762fa6355e258601dfb49dda6f672092ae5adf072d5cab2ceaaa0d68dd3fe7fa04869d95afed8c20069f446a338576901e1b"}; J. r+ A3 t1 m+ C+ S
logger.info("private key 1:" + privateKeys[0]);
logger.info("private key 2:" + privateKeys[1]);
// call offline sign method to obtain a basic offline signed template3 P+ N# m! w8 L( G. ^
Signatures signatures = new SignaturesImpl();/ Q* V8 ~9 x' h( }* ]3 o4 \# N
Template basicSigned = signatures.generateSignatures(privateKeys, template, decodedTx);
logger.info("basic signed raw: " + basicSigned.toJson());
// call sign transaction api to calculate whole raw_transaction id
// sign password is None or another random String1 o( Q- C& Y+ m4 L/ c( ]8 u
Template result = new Transaction.SignerBuilder().sign(client,3 m! l8 S' l% N6 O; M0 P4 D, P d* {
basicSigned, "");+ ^2 U9 V$ s6 z
logger.info("result raw_transaction: " + result.toJson());
// success to submit transaction
}
Multi-keys and Multi-inputs Example: R* z* O! r' K; s, b1 n
@Test
// 使用 SDK 来构造 Template 对象参数, 多签, 多输入
public void testSignMultiKeysMultiInputs() throws BytomException {
Client client = Client.generateClient();+ a% G- K+ G( y! [, [
String asset_id = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
String address = "sm1qvyus3s5d7jv782syuqe3qrh65fx23lgpzf33em"; v( X* ?( o4 S7 c9 Z9 Z
// build transaction obtain a Template object2 E1 }: R6 u- I( E. n6 S8 W
Template template = new Transaction.Builder()
.setTtl(10)
// 1 input1 z* L9 \$ _0 @( x* B2 I
.addAction( z, p9 Y, o# r1 H; A) s7 G
new Transaction.Action.SpendFromAccount()8 ?. t; [; d3 Z, U
.setAccountId("0G1RPP6OG0A06") // Multi-keys account. s6 r$ |2 q% j% a1 e2 P
.setAssetId(asset_id)
.setAmount(40000000)$ [6 k' E7 ^7 S, }" P+ T+ ]; K
)
.addAction(
new Transaction.Action.SpendFromAccount()
.setAccountId("0G1RPP6OG0A06")
.setAssetId(asset_id)
.setAmount(300000000)
) // 2 input# v( G I; @3 U/ M% o9 m5 X1 F
.addAction(
new Transaction.Action.SpendFromAccount()1 V3 O, {4 d( {: F& O& Y( G
.setAccountId("0G1Q6V1P00A02") // Multi-keys account$ c$ N3 T4 w* A, T4 q& e4 u
.setAssetId(asset_id)
.setAmount(40000000)
)
.addAction(. W& ]' |. o* X7 {+ E
new Transaction.Action.SpendFromAccount()
.setAccountId("0G1Q6V1P00A02")
.setAssetId(asset_id) p, W8 u+ `% m" M5 h& e
.setAmount(300000000)
)* u$ C1 F+ t, \
.addAction(, m* U$ }( q* O
new Transaction.Action.ControlWithAddress()
.setAddress(address)
.setAssetId(asset_id)" ^! ?. G- u) ^! X, C. @* o
.setAmount(60000000)
).build(client);4 E. z" ?" U7 j j" N
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);1 V! x, X i* V8 _+ @8 m7 p
logger.info("decodeTx: " + decodedTx.toJson());
// need a private key array* B6 ?# W3 V6 \1 }2 e( z
String[] privateKeys = new String[]{"08bdbd6c22856c5747c930f64d0e5d58ded17c4473910c6c0c3f94e485833a436247976253c8e29e961041ad8dfad9309744255364323163837cbef2483b4f67",8 E. l% r8 V; M
"40c821f736f60805ad59b1fea158762fa6355e258601dfb49dda6f672092ae5adf072d5cab2ceaaa0d68dd3fe7fa04869d95afed8c20069f446a338576901e1b",
"08bdbd6c22856c5747c930f64d0e5d58ded17c4473910c6c0c3f94e485833a436247976253c8e29e961041ad8dfad9309744255364323163837cbef2483b4f67"}; w! }* v" Q& P0 @& r" r
logger.info("private key 1:" + privateKeys[0]);
logger.info("private key 2:" + privateKeys[1]);
// call offline sign method to obtain a basic offline signed template' C5 v/ i7 p! x s9 y/ r
Signatures signatures = new SignaturesImpl();; b( W& Z- K: w& ?0 X
Template basicSigned = signatures.generateSignatures(privateKeys, template, decodedTx);
logger.info("basic signed raw: " + basicSigned.toJson());" }' K5 {/ A) P7 _# P- E" P
// call sign transaction api to calculate whole raw_transaction id* U; u+ l1 v- v) c0 W
// sign password is None or another random String
Template result = new Transaction.SignerBuilder().sign(client,
basicSigned, "");
logger.info("result raw_transaction: " + result.toJson());& t# O" ^" K/ K
// success to submit transaction
}