交易简介

youchain.java支持三种类型的YOUChain交易:

1、转账交易:YOU从一方交易到另一方 2、创建智能合约 3、与智能合约进行交互

为了进行这些交易,你必须拥有一个有效的钱包帐户(没有钱包账户?点击这里),而且账户中必须有足够到YOU(YOUChain区块链的代币)。这是为了支付gas成本,支付了gas成本就能将结果提交到YOUChain区块链上。

下面介绍了交易所需的关键属性。

  • Gas price 燃料价格
  • Gas limit 燃料限制
  • Nonce 交易随机数
  • from 发送地址
  • to 接收地址

gas成本

当在YOUChain发生交易时,必须为执行该交易的客户端支付交易成本,将该交易的输出提交到YOUChain区块链。

此成本是通过gas来测量的,其中gas是用于在YOUChain虚拟机中执行交易指令的数量。

有两个参数用来指示你希望花费多少YOU来完成传输:

BigInteger gasPrice = youChain.youGasPrice().send().getGasPrice();

你可能需要调整这些参数以确保交易能及时进行。

lu

关于计量单位请参照术语表-计量单位

可以使用Convert类来进行YOU和lu之间的转换

BigInteger amountLu = Convert.toLu(amount, Convert.Unit.YOU).toBigInteger();

注意:发起交易请求时请将金额单位换算成lu进行交易,查询交易时返回值默认单位是lu,若想转化成you请使用

BigDecimal amountYou = Convert.fromLu(amount, Convert.Unit.YOU);

交易随机数Nonce

nonce是一个不断增长的数值,用来唯一地标识交易。
一个nonce只能使用一次,直到交易被挖掘完成,可以以相同的随机数发送交易的多个版本,但是一旦其中一个被挖掘完成,其他后续提交的都将被拒绝。

可以通过RPC接口you_getTransactionCount方法获得下一个可用的nonce:

YOUGetTransactionCount youGetTransactionCount = youChain.youGetTransactionCount(
             address, DefaultBlockParameterName.LATEST).sendAsync().get();
BigInteger nonce = youGetTransactionCount.getTransactionCount();

然后可以使用nonce创建你的交易对象:

RawTransaction rawTransaction  = RawTransaction.createYOUTransaction(
             nonce, <gas price>, <gas limit>, <toAddress>, <value>);

离线交易签名认证

如果你不想管理自己的YOUChain客户端,或者不想向YOUChain客户端提供诸如密码之类的钱包详细信息,那么就通过离线交易认证签名。

离线交易签名认证允许你在youchain.java中使用你的YOUChain钱包签署交易,允许你完全控制你的私有凭据。

然后,离线创建的交易可以被发送到网络上的任何YOUChain客户端,只要它是一个有效的交易,它会将交易传播到其他节点。

如果需要,还可以执行进程外交易签名认证。这可以通过重写ECKeyPair的sign方法来实现。

要使离线签名交易得到签署,需要设定一个RawTransaction类型。RawTransaction不需要通过具体的账号地址来请求,因为可以从签名中推断出来。

为了创建和签署原生交易,交易的顺序如下:

1、确定交易发起者帐户的下一个可用随机数nonce

2、创建RawTransaction对象

3、使用递归长度前缀编码(RLP即Recursive Length Prefix)对RawTransaction对象进行编码

4、签署RawTransaction对象

5、将RawTransaction对象发送到节点进行处理 nonce是一个不断增长的数值,用来唯一地标识交易。一个nonce只能使用一次,直到交易被挖掘完成,可以以相同的随机数发送交易的多个版本, 但是一旦其中一个被挖掘完成,其他后续提交的都将被拒绝。 一旦获得下一个可用的nonce,该值就可以用来创建transaction对象:

RawTransaction rawTransaction  = RawTransaction.createYOUTransaction(
             nonce, <gas price>, <gas limit>, <toAddress>, <value>);

然后可以对交易进行签名和编码:

byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, <credentials>);
String signedTransactionData = Numeric.toHexString(signedMessage);
String transactionHash = youChain.youSendRawTransaction(signedTransactionData).send().getTransactionHash();
// poll for transaction response via youChain.youGetTransactionReceipt(<txHash>)

注意:创建RawTransaction时只需要toAddress,因为发送者可以通过签名信息中推断出。

在交易中指定链程序网络ID

RawTransactionManager采用一个可选的链表参数来指定在交易使用的链程序网络ID。这防止了一个链被重新广播到另一个链上的交易,例如从测试链到 Mainnet。

TransactionManager transactionManager = new RawTransactionManager(youchain, credentials, NetworkId.MAINNET);

为了避免更改配置或代码来指定你正在使用的链,youchain默认是不指定交易上的链程序网络ID,以简化与库间的交互。然而,建议使用链ID。 你可以通过以下请求获得你的YOUChain客户端连接到的网络的链程序网络ID:

youchain.netVersion().send().getNetVersion();

目前提供主网和测试网络两个链程序网络ID

public class NetworkId {
    public static final byte NONE = -1;
    public static final byte MAINNET = 1;
    public static final byte TESTNET = 2;
}

获取交易凭证

若交易还未确认或者交易失败,返回的transactionReceipt都是null。 同步方法

YOUGetTransactionReceipt youGetTransactionReceipt = youChain.youGetTransactionReceipt(transactionHash).send();
TransactionReceipt transactionReceipt = youGetTransactionReceipt.getTransactionReceipt().orElse(null);

异步方法

CompletableFuture<YOUGetTransactionReceipt> completableFuture = youChain.youGetTransactionReceipt(transactionHash).sendAsync();
completableFuture.thenAccept(c -> {
    TransactionReceipt receipt = c.getTransactionReceipt().get();
});

交易管理器及凭证处理器

默认情况下,当提交新的交易时,youchain.java将继续轮询客户端直到收到TransactionReceipt,指示交易已被添加提交到区块链上。
如果你异步发送多个交易,则这会导致多个线程同时轮询客户端。为了减少这种轮询开销,你可以选中不同的交易收据处理器TransactionReceiptProcessors。
youchain.java提供三种凭证处理器,与交易管理器配合使用,分别如下: 1、NoOpProcessor 不做任何处理,返回一个空到交易凭证以及交易hash,那些不需要对交易凭证进行处理的用户可以使用。 2、PollingTransactionReceiptProcessor (默认的处理器)使用当前线程轮询,直到查询出交易凭证 3、QueuingTransactionReceiptProcessor 直接返回空凭证,并把任务提交给一个任务队列定时轮询交易结果,获得结果后可以根据callback进行回调

交易管理器TransactionManager来控制你连接到YOUChain客户端的方式,youchain.java提供四种交易管理器,分别如下: 1、ClientTransactionManager 提供使用YOUChain节点进行交易的实现,它将你的交易签署的责任传递给你正在连接的YOUChain客户端。 注意:账户必须在该节点上先进行解锁操作,交易才能正常触发。 2、RawTransactionManager 提供使用YOUChain钱包文件来创建交易并在和提交到网络之前离线签名的实现 3、FastRawTransactionManager 是RawTransactionManager的子类,提供可管理nonce的操作实现,好处是多次进行交易时,使用该管理器不需要自己维护一套nonce的递增逻辑 4、ReadonlyTransactionManager 仅提供智能合约的只读操作的实现 交易管理器需要与交易凭证处理器配合使用,如果不明确指定交易凭证处理器,默认使用的是PollingTransactionReceiptProcessor。

PollingTransactionReceiptProcessor示例:

int attempts = 10, sleepDuration = 1000;
byte networkId = NetworkId.TESTNET; // 主网请使用 NetworkId.MAINNET
TransactionReceiptProcessor processor = new PollingTransactionReceiptProcessor(youChain, attempts, sleepDuration);
TransactionManager transactionManager = new RawTransactionManager(youChain, credential, networkId, processor);
TransactionReceipt transactionReceipt = transactionManager.executeTransaction(gasPrice, gasLimit, toAddress, "", amount);

QueuingTransactionReceiptProcessor示例:

int attempts = 50;
long frequency = 300;
byte networkId = NetworkId.TESTNET; // 主网请使用 NetworkId.MAINNET
AsyncTransCallback callback = new AsyncTransCallback();
TransactionReceiptProcessor processor = new QueuingTransactionReceiptProcessor(youChain, callback, attempts, frequency);
TransactionManager transactionManager = new RawTransactionManager(youChain, credential, networkId, processor);
TransactionReceipt transactionReceipt = transactionManager.executeTransaction(gasPrice, gasLimit, toAddress, "", amount);
// 注意:此transactionReceipt是一个EmptyTransactionReceipt,只能用来获取transactionHash
String transactionHash = transactionReceipt.getTransactionHash();
public class AsyncTransCallback implements Callback {
    @Override
    public void accept(TransactionReceipt transactionReceipt) {
        // 根据凭证处理业务
    }
    @Override
    public void exception(Exception exception) {
        // 处理异常逻辑
    }
}

FastRawTransactionManager示例,不需要自己管理Nonce:

TransactionManager transactionManager = new FastRawTransactionManager(youChain, credential, networkId);
YOUSendTransaction transactionA = transactionManager.sendTransaction(gasPrice, gasLimit, toAddressA, "", amountA);
YOUSendTransaction transactionB = transactionManager.sendTransaction(gasPrice, gasLimit, toAddressB, "", amountB);