通过bitcoinj付款的正确方法

时间:2016-09-18 09:58:19

标签: java bitcoin bitcoinj bitcoin-testnet

我正在尝试通过bitcoinj(版本0.14.3)进行交易,我希望在付款后能够获得更改。我正在使用testnet,它不是真正的比特币。 我有下一个代码:

Transaction tx = new Transaction(this.networkParameters);
Coin coinToSent = Coin.valueOf(Config.APP_COST);
Coin coinToChange = Coin.valueOf(walletBalance.getValue() - coinToSent.getValue());
tx.addOutput(coinToSent, appAddress);
tx.addOutput(coinToChange, changeAddress);

SendRequest request = SendRequest.forTx(tx);
try {
    this.walletAppKit.wallet().completeTx(request);
} catch (InsufficientMoneyException e) {
    e.printStackTrace();
    return false;
}
this.walletAppKit.wallet().commitTx(request.tx);
this.walletAppKit.peerGroup().broadcastTransaction(request.tx); 

所以,我将两个输出放入交易中:

  1. 汇款地址
  2. 我的钱包的地址,以便获得更改
  3. 到第一个地址我发了一些钱。到第二个地址,我发送下一个值:我钱包上的所有可用资金减去收到第一个地址的钱。

    但是在播出后我有一个意想不到的结果。在用这个方案做了几笔交易之后,我发现从我的钱包里退出了错误的价值。令人惊讶的是,有时钱正在退出,但有时钱会流入钱包。

    Here is the link to testnet explorer

    有人可以解释我做错了什么以及如何解决它?

1 个答案:

答案 0 :(得分:0)

交易没有按预期工作的原因是Bitcoinj Wallet类在后台为您做了很多事情 - 在这种情况下,它会自动生成一个更改地址,其中将存储更改交易。另一个因素是比特币计算了一个费用,它会让矿工处理交易,这就是为什么你会看到更改地址获得你所要求的更少的硬币(在生产网络上它会抛出异常,如果你没有足够的资金支付费用。)

我认为,对于相对简单的情况,此处的最佳解决方案是使用Wallet API并让它自动生成更改地址(它使用确定性钥匙串,因此所有地址和如果丢失钱包,可以重新生成密钥)。例如:

public static Transaction send(Wallet wallet, 
                               String destinationAddress, 
                               long satoshis) throws Exception {
  Address dest = Address.fromBase58(params, destinationAddress);
  SendRequest request = SendRequest.to(dest, Coin.valueOf(satoshis));
  SendResult result = wallet.sendCoins(request);
  Transaction endTransaction = result.broadcastComplete.get();
  return endTransaction;
}

完成sendCoins并广播交易后,钱包将保留其余部分(如果您确实想要确保拥有更改地址的密钥,则可以在transactin完成后将其保存到文件中),此处和#39;您可以看到10个更改地址及其公钥/私钥的列表:

NetworkParameters params = new MainNetParams();
List<DeterministicKey> keys = wallet.freshKeys(KeyChain.KeyPurpose.CHANGE, 10);
keys.forEach(key -> {
  Address address = new Address(params, key.getPubKeyHash());
  System.out.println(address +" : " + key.toStringWithPrivate(params));
});