From 821e8ae3cdd36b003b17fa6a700ea6677329f7dc Mon Sep 17 00:00:00 2001 From: successli Date: Fri, 1 Jun 2018 16:04:47 +0800 Subject: [PATCH] add some details to transactions.md file --- doc/transactions.md | 215 ++++++++++++-- .../java/io/bytom/integration/TransactionTest.java | 321 +++++++++++---------- 2 files changed, 361 insertions(+), 175 deletions(-) diff --git a/doc/transactions.md b/doc/transactions.md index a5192d9..c355ce0 100644 --- a/doc/transactions.md +++ b/doc/transactions.md @@ -32,29 +32,210 @@ Once a transaction is balanced and all inputs are signed, it is considered valid The Chain Core API does not return a response until either the transaction has been added to the blockchain and indexed by the local core, or there was an error. This allows you to write your applications in a linear fashion. In general, if a submission responds with success, the rest of your application may proceed with the guarantee that the transaction has been committed to the blockchain. - - ## Examples ### Asset issuance +Issue 1000 units of gold to Alice. + +#### Within a Chain Core + +```java +Transaction.Template issuance = new Transaction.Builder() + .addAction(new Transaction.Action.Issue() + .setAssetAlias("gold") + .setAmount(1000) + ).addAction(new Transaction.Action.ControlWithAccount() + .setAccountAlias("alice") + .setAssetAlias("gold") + .setAmount(1000) + ).build(client); + +Transaction.Template signedIssuance = new Transaction.SignerBuilder().sign(client, + issuance, "123456"); + +Transaction.submit(client, signedIssuance); +``` + +#### Between two Chain Cores + +First, Bob creates a receiver in his account, which he can serialize and send to the issuer of gold. + +```java +Receiver bobIssuanceReceiver = new Account.ReceiverBuilder() + .setAccountAlias("bob") + .create(otherCoreClient); +String bobIssuanceReceiverSerialized = bobIssuanceReceiver.toJson(); +``` + +The issuer then builds, signs, and submits a transaction, sending gold to Bob’s receiver. + +```java +Transaction.Template issuanceToReceiver = new Transaction.Builder() + .addAction(new Transaction.Action.Issue() + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.ControlWithReceiver() + .setReceiver(Receiver.fromJson(bobIssuanceReceiverSerialized)) + .setAssetAlias("gold") + .setAmount(10) + ).build(client); + +Transaction.Template signedIssuanceToReceiver = new Transaction.SignerBuilder().sign(client, + issuanceToReceiver, "123456"); + +Transaction.submit(client, signedIssuanceToReceiver); +``` + +### Simple payment + +Alice pays 10 units of gold to Bob. + +#### Within a Chain Core + +```java +Transaction.Template payment = new Transaction.Builder() + .addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.ControlWithAccount() + .setAccountAlias("bob") + .setAssetAlias("gold") + .setAmount(10) + ).build(client); + +Transaction.Template signedPayment = new Transaction.SignerBuilder().sign(client, + payment, "123456"); + +Transaction.submit(client, signedPayment); +``` + +#### Between two Chain Cores + +First, Bob creates a receiver in his account, which he can serialize and send to Alice. + +```java +Receiver bobPaymentReceiver = new Account.ReceiverBuilder() + .setAccountAlias("bob") + .create(otherCoreClient); +String bobPaymentReceiverSerialized = bobPaymentReceiver.toJson(); +``` + +Alice then builds, signs, and submits a transaction, sending gold to Bob’s receiver. + +```java +Transaction.Template paymentToReceiver = new Transaction.Builder() + .addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.ControlWithReceiver() + .setReceiver(Receiver.fromJson(bobPaymentReceiverSerialized)) + .setAssetAlias("gold") + .setAmount(10) + ).build(client); + +Transaction.Template signedPaymentToReceiver = new Transaction.SignerBuilder().sign(client, + paymentToReceiver, "123456"); + +Transaction.submit(client, signedPaymentToReceiver); +``` + +### Multi-asset payment + +Alice pays 10 units of gold and 20 units of silver to Bob. + +#### Within a Chain Core + ```java -Transaction.Template controlAddress = new Transaction.Builder() - .addAction( - new Transaction.Action.SpendFromAccount() - .setAccountId(senderAccount.id) - .setAssetId(senderAsset.id) - .setAmount(300000000) - ) - .addAction( - new Transaction.Action.ControlWithAddress() - .setAddress(receiverAddress.address) - .setAssetId(senderAsset.id) - .setAmount(200000000) - ).build(client); +Transaction.Template multiAssetPayment = new Transaction.Builder() + .addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("silver") + .setAmount(20) + ).addAction(new Transaction.Action.ControlWithAccount() + .setAccountAlias("bob") + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.ControlWithAccount() + .setAccountAlias("bob") + .setAssetAlias("silver") + .setAmount(20) + ).build(client); + +Transaction.Template signedMultiAssetPayment = new Transaction.SignerBuilder().sign(client, + multiAssetPayment, "123456"); + +Transaction.submit(client, signedMultiAssetPayment); +``` -Transaction.Template singer = new Transaction.SignerBuilder().sign(client, controlAddress, "123456"); +#### Between two Chain Cores -Transaction.SubmitResponse txs = Transaction.submit(client, singer); +Currently, the transaction builder API assigns each receiver to its own output, which means that a single receiver can only be used to receive a single asset type. It’s important for Bob not to re-use receivers, so he creates one for each asset payment he will receive. He serializes both and sends them to Alice. + +```java +Receiver bobGoldReceiver = new Account.ReceiverBuilder() + .setAccountAlias("bob") + .create(otherCoreClient); +String bobGoldReceiverSerialized = bobGoldReceiver.toJson(); + +Receiver bobSilverReceiver = new Account.ReceiverBuilder() + .setAccountAlias("bob") + .create(otherCoreClient); +String bobSilverReceiverSerialized = bobSilverReceiver.toJson(); +``` + +Alice then builds, signs, and submits a transaction, sending gold and silver to Bob’s receivers. + +```java +Transaction.Template multiAssetToReceiver = new Transaction.Builder() + .addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("silver") + .setAmount(20) + ).addAction(new Transaction.Action.ControlWithReceiver() + .setReceiver(Receiver.fromJson(bobGoldReceiverSerialized)) + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.ControlWithReceiver() + .setReceiver(Receiver.fromJson(bobSilverReceiverSerialized)) + .setAssetAlias("silver") + .setAmount(20) + ).build(client); + +Transaction.Template signedMultiAssetToReceiver = new Transaction.SignerBuilder().sign(client, + multiAssetToReceiver, "123456"); + +Transaction.submit(client, signedMultiAssetToReceiver); +``` + +### Asset retirement + +Alice retires 50 units of gold from her account. + +```java +Transaction.Template retirement = new Transaction.Builder() + .addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("gold") + .setAmount(50) + ).addAction(new Transaction.Action.Retire() + .setAssetAlias("gold") + .setAmount(50) + ).build(client); + +Transaction.Template signedRetirement = new Transaction.SignerBuilder().sign(client, + retirement, "123456"); + +Transaction.submit(client, signedRetirement); ``` diff --git a/src/test/java/io/bytom/integration/TransactionTest.java b/src/test/java/io/bytom/integration/TransactionTest.java index a03b405..90d01b9 100644 --- a/src/test/java/io/bytom/integration/TransactionTest.java +++ b/src/test/java/io/bytom/integration/TransactionTest.java @@ -17,14 +17,12 @@ import static org.junit.Assert.assertNotNull; public class TransactionTest { static Client client; + static Client otherCoreClient; static Key senderKey; static Key receiverKey; static Account senderAccount; static Account receiverAccount; - static Receiver senderReceiver; - static Receiver receiverReceiver; - static Account.Address senderAddress; static Account.Address receiverAddress; static Asset senderAsset; static Asset receiverAsset; @@ -34,6 +32,7 @@ public class TransactionTest { static { try { client = TestUtils.generateClient(); + otherCoreClient = TestUtils.generateClient(); } catch (BytomException e) { e.printStackTrace(); } @@ -42,46 +41,30 @@ public class TransactionTest { private static Logger logger = Logger.getLogger(TransactionTest.class); - @Test - public void testCreateAll() throws Exception { - - testSenderKeyCreate(); - testReceiverKeyCreate(); - - testSenderAccountCreate(); - testReceiverAccountCreate(); - -// testSenderReceiverCreate(); - testReceiverReceiverCreate(); - -// testSenderAssetCreate(); -// testReceiverAssetCreate(); - - } @Test public void testGetAll() throws Exception { senderKey = Key.list(client).get(0); receiverKey = Key.list(client).get(1); - logger.info("senderKey:"+senderKey.toJson()); - logger.info("receiverKey:"+receiverKey.toJson()); + logger.info("senderKey:" + senderKey.toJson()); + logger.info("receiverKey:" + receiverKey.toJson()); senderAccount = Account.list(client).get(0); receiverAccount = Account.list(client).get(1); - logger.info("senderAccount:"+senderAccount.toJson()); - logger.info("receiverAccount:"+receiverAccount.toJson()); + logger.info("senderAccount:" + senderAccount.toJson()); + logger.info("receiverAccount:" + receiverAccount.toJson()); receiverAddress = new Account.AddressBuilder() .setAccountAlias(receiverAccount.alias) .setAccountId(receiverAccount.id) .list(client).get(0); - logger.info("receiver-address:"+receiverAddress.toJson()); + logger.info("receiver-address:" + receiverAddress.toJson()); senderAsset = new Asset.QueryBuilder().list(client).get(0); receiverAsset = new Asset.QueryBuilder().list(client).get(1); - logger.info("senderAsset:"+senderAsset.toJson()); - logger.info("receiverAsset:"+receiverAsset.toJson()); + logger.info("senderAsset:" + senderAsset.toJson()); + logger.info("receiverAsset:" + receiverAsset.toJson()); } @Test @@ -111,13 +94,13 @@ public class TransactionTest { Transaction.Template singer = new Transaction.SignerBuilder().sign(client, controlAddress, "123456"); - logger.info("rawTransaction:"+singer.rawTransaction); + logger.info("rawTransaction:" + singer.rawTransaction); - logger.info("singer:"+singer.toJson()); + logger.info("singer:" + singer.toJson()); Transaction.SubmitResponse txs = Transaction.submit(client, singer); - logger.info("txs:"+txs.toJson()); + logger.info("txs:" + txs.toJson()); logger.info("after transaction."); @@ -125,163 +108,185 @@ public class TransactionTest { } + //Asset issuance + //Issue 1000 units of gold to Alice. @Test - public void testListTransactions() throws Exception { - List transactionList = new Transaction.QueryBuilder().list(client); - } - - @Test - public void testListByIdTransactions() throws Exception { - String tx_id = "f04d4d9b2580ff6496f9f08d903de5a2365975fb8d65b66ca4259f152c5dd134"; - List transactionList = - new Transaction.QueryBuilder().setTxId(tx_id).list(client); - for (Transaction tx: transactionList - ) { - if (tx.txId.equalsIgnoreCase(tx_id)) { - logger.info("this transaction is :"); - logger.info(tx.toJson()); - } - } - } - - @Test - public void testListByAccountIdTransactions() throws Exception { - String account_id = "0E6KP8C100A02"; - List transactionList = - new Transaction.QueryBuilder().setAccountId(account_id).list(client); - } - - public void testSenderKeyCreate() throws Exception { - String alias = "sender-key"; - String password = "123456"; - - Key.Builder builder = new Key.Builder().setAlias(alias).setPassword(password); - senderKey = Key.create(client, builder); - - logger.info("create-sender-key:"+senderKey.toJson()); - } - - public void testReceiverKeyCreate() throws Exception { - String alias = "receiver-key"; - String password = "123456"; - - Key.Builder builder = new Key.Builder().setAlias(alias).setPassword(password); - receiverKey = Key.create(client, builder); - - logger.info("create-receiver-key:"+receiverKey.toJson()); - } - - public void testSenderAccountCreate() throws Exception { - String alias = "sender-account"; - Integer quorum = 1; - List root_xpubs = new ArrayList(); - root_xpubs.add(senderKey.xpub); - - Account.Builder builder = new Account.Builder().setAlias(alias).setQuorum(quorum).setRootXpub(root_xpubs); - - logger.info(builder.toString()); + public void testAssetIssue() throws BytomException { + Transaction.Template issuance = new Transaction.Builder() + .addAction(new Transaction.Action.Issue() + .setAssetAlias("gold") + .setAmount(1000) + ).addAction( + new Transaction.Action.ControlWithAccount() + .setAccountAlias("alice") + .setAssetAlias("golad") + .setAmount(1000) + ).build(client); - senderAccount = Account.create(client, builder); + Transaction.Template signedIssuance = new Transaction.SignerBuilder().sign(client, + issuance, "123456"); - logger.info("create-sender-account:"+senderAccount.toJson()); + Transaction.submit(client, signedIssuance); } - public void testReceiverAccountCreate() throws Exception { - String alias = "receiver-account"; - Integer quorum = 1; - List root_xpubs = new ArrayList<>(); - root_xpubs.add(receiverKey.xpub); + //Between two Chain Cores + @Test + public void testAssetIssueBetween() throws BytomException { + Receiver bobIssuanceReceiver = new Account.ReceiverBuilder() + .setAccountAlias("bob") + .create(otherCoreClient); + String bobIssuanceReceiverSerialized = bobIssuanceReceiver.toJson(); + + + Transaction.Template issuanceToReceiver = new Transaction.Builder() + .addAction(new Transaction.Action.Issue() + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.ControlWithReceiver() + .setReceiver(Receiver.fromJson(bobIssuanceReceiverSerialized)) + .setAssetAlias("gold") + .setAmount(10) + ).build(client); - Account.Builder builder = new Account.Builder().setAlias(alias).setQuorum(quorum).setRootXpub(root_xpubs); - receiverAccount = Account.create(client, builder); + Transaction.Template signedIssuanceToReceiver = new Transaction.SignerBuilder().sign(client, + issuanceToReceiver, "123456"); - logger.info("create-receiver-account:"+receiverAccount.toJson()); + Transaction.submit(client, signedIssuanceToReceiver); } - public void testSenderReceiverCreate() throws Exception { - String alias = senderAccount.alias; - String id = senderAccount.id; + //Simple payment + //Alice pays 10 units of gold to Bob. + @Test + public void testSimplePayment() throws BytomException { + Transaction.Template payment = new Transaction.Builder() + .addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.ControlWithAccount() + .setAccountAlias("bob") + .setAssetAlias("gold") + .setAmount(10) + ).build(client); - Account.ReceiverBuilder receiverBuilder = new Account.ReceiverBuilder().setAccountAlias(alias).setAccountId(id); - senderReceiver = receiverBuilder.create(client); + Transaction.Template signedPayment = new Transaction.SignerBuilder().sign(client, + payment, "123456"); - logger.info("create-receiver:"+senderReceiver.toJson()); - logger.info("receiver-address:"+senderReceiver.address); + Transaction.submit(client, signedPayment); } - public void testReceiverReceiverCreate() throws Exception { - String alias = receiverAccount.alias; - String id = receiverAccount.id; + //Between two Chain Cores + @Test + public void testSimplePaymentBetween() throws BytomException { + Receiver bobPaymentReceiver = new Account.ReceiverBuilder() + .setAccountAlias("bob") + .create(otherCoreClient); + String bobPaymentReceiverSerialized = bobPaymentReceiver.toJson(); + + + Transaction.Template paymentToReceiver = new Transaction.Builder() + .addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.ControlWithReceiver() + .setReceiver(Receiver.fromJson(bobPaymentReceiverSerialized)) + .setAssetAlias("gold") + .setAmount(10) + ).build(client); - Account.ReceiverBuilder receiverBuilder = new Account.ReceiverBuilder().setAccountAlias(alias).setAccountId(id); - receiverReceiver = receiverBuilder.create(client); + Transaction.Template signedPaymentToReceiver = new Transaction.SignerBuilder().sign(client, + paymentToReceiver, "123456"); - logger.info("create-receiver:"+receiverReceiver.toJson()); - logger.info("receiver-address:"+receiverReceiver.address); + Transaction.submit(client, signedPaymentToReceiver); } - public void testSenderAssetCreate() throws Exception { - String alias = "sender-asset"; - - List xpubs = senderAccount.xpubs; + //Multi-asset payment + //Alice pays 10 units of gold and 20 units of silver to Bob. + @Test + public void testMultiAssetPayment() throws BytomException { + Transaction.Template multiAssetPayment = new Transaction.Builder() + .addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("silver") + .setAmount(20) + ).addAction(new Transaction.Action.ControlWithAccount() + .setAccountAlias("bob") + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.ControlWithAccount() + .setAccountAlias("bob") + .setAssetAlias("silver") + .setAmount(20) + ).build(client); - Asset.Builder builder = new Asset.Builder() - .setAlias(alias) - .setQuorum(1) - .setRootXpubs(xpubs); - senderAsset = builder.create(client); + Transaction.Template signedMultiAssetPayment = new Transaction.SignerBuilder().sign(client, + multiAssetPayment, "123456"); - logger.info("create-sender-asset:"+senderAsset.toJson()); + Transaction.submit(client, signedMultiAssetPayment); } - public void testReceiverAssetCreate() throws Exception { - String alias = "receiver-asset"; - - List xpubs = receiverAccount.xpubs; + //Between two Chain Cores + @Test + public void testMultiAssetPaymentBetween() throws BytomException { + Receiver bobGoldReceiver = new Account.ReceiverBuilder() + .setAccountAlias("bob") + .create(otherCoreClient); + String bobGoldReceiverSerialized = bobGoldReceiver.toJson(); + + Receiver bobSilverReceiver = new Account.ReceiverBuilder() + .setAccountAlias("bob") + .create(otherCoreClient); + String bobSilverReceiverSerialized = bobSilverReceiver.toJson(); + + + Transaction.Template multiAssetToReceiver = new Transaction.Builder() + .addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("silver") + .setAmount(20) + ).addAction(new Transaction.Action.ControlWithReceiver() + .setReceiver(Receiver.fromJson(bobGoldReceiverSerialized)) + .setAssetAlias("gold") + .setAmount(10) + ).addAction(new Transaction.Action.ControlWithReceiver() + .setReceiver(Receiver.fromJson(bobSilverReceiverSerialized)) + .setAssetAlias("silver") + .setAmount(20) + ).build(client); - Asset.Builder builder = new Asset.Builder() - .setAlias(alias) - .setQuorum(1) - .setRootXpubs(xpubs); - receiverAsset = builder.create(client); + Transaction.Template signedMultiAssetToReceiver = new Transaction.SignerBuilder().sign(client, + multiAssetToReceiver, "123456");; - logger.info("create-receiver-asset:"+receiverAsset.toJson()); + Transaction.submit(client, signedMultiAssetToReceiver); } - /** - * build + sign + submit transaction - * - * @throws BytomException - */ - public void testBasicTransaction() throws BytomException { - logger.info("before transaction:"); - - List balanceList = new Balance.QueryBuilder().list(client); - - logger.info(balanceList.get(0).toJson()); - logger.info(balanceList.get(1).toJson()); - - Transaction.Template controlAddress = new Transaction.Builder() - .addAction( - new Transaction.Action.SpendFromAccount() - .setAccountId(senderAccount.id) - .setAssetId(senderAsset.id) - .setAmount(300000000) - ) - .addAction( - new Transaction.Action.ControlWithAddress() - .setAddress(receiverAddress.address) - .setAssetId(receiverAsset.id) - .setAmount(200000000) + //Asset retirement + //Alice retires 50 units of gold from her account. + @Test + public void testRetirement() throws BytomException { + Transaction.Template retirement = new Transaction.Builder() + .addAction(new Transaction.Action.SpendFromAccount() + .setAccountAlias("alice") + .setAssetAlias("gold") + .setAmount(50) + ).addAction(new Transaction.Action.Retire() + .setAssetAlias("gold") + .setAmount(50) ).build(client); - logger.info("after transaction."); - - balanceList = new Balance.QueryBuilder().list(client); - - logger.info(balanceList.get(0).toJson()); - logger.info(balanceList.get(1).toJson()); + Transaction.Template signedRetirement = new Transaction.SignerBuilder().sign(client, + retirement, "123456"); + Transaction.submit(client, signedRetirement); } //TransactionFeed -- 2.11.0