修改了examples/build.gradle,添加了application插件,使得gradle可以运行指定例子,如通过mainClass指定要运行类,gradle -PmainClass=org.bitcoinj.examples.FetchBlock run --args=000000000000001535467706e8545b339e7e0adca408c5432781f4da0e94d734,改动如图3-3所示。
Wallet.SendResult result = wallet.sendCoins(req);
...
public CoinSelection select(Coin target, List<TransactionOutput> candidates) {
ArrayList<TransactionOutput> selected = new ArrayList<>();
// Sort the inputs by age*value so we get the highest "coindays" spent.
// TODO: Consider changing the wallets internal format to track just outputs and keep them ordered.
ArrayList<TransactionOutput> sortedOutputs = new ArrayList<>(candidates);
// When calculating the wallet balance, we may be asked to select all possible coins, if so, avoid sorting
// them in order to improve performance.
if (!target.equals(BitcoinNetwork.MAX_MONEY)) {
sortedOutputs.sort(DefaultCoinSelector::compareByDepth);
}
// Now iterate over the sorted outputs until we have got as close to the target as possible or a little
// bit over (excessive value will be change).
long total = 0;
for (TransactionOutput output : sortedOutputs) {
if (total >= target.value) break;
// Only pick chain-included transactions, or transactions that are ours and pending.
if (!shouldSelect(output.getParentTransaction())) continue;
selected.add(output);
total = Math.addExact(total, output.getValue().value);
}
// Total may be lower than target here, if the given candidates were insufficient to create to requested
// transaction.
return new CoinSelection(selected);
}
WalletAppKit kit =WalletAppKit.launch(network,newFile("."),"walletappkit-example", (k) -> {// In case you want to connect with your local bitcoind tell the kit to connect to localhost.// This is done automatically in reg test mode.// k.connectToLocalHost();try {k.setPeerNodes(PeerAddress.simple(InetAddress.getByName("127.0.0.1"),18333)); // 设置本地连接Peer节点 } catch (UnknownHostException e) {e.printStackTrace(); } });
正常情况下,使用本地全节点能避免很多问题。
bitcoinj常见问题
1.钱包加载异常
Exception in thread "main" java.lang.IllegalStateException: Expected the service WalletAppKit [FAILED] to be RUNNING, but the service has FAILED
at com.google.common.util.concurrent.AbstractService.checkCurrentState(AbstractService.java:384)
at com.google.common.util.concurrent.AbstractService.awaitRunning(AbstractService.java:308)
at com.google.common.util.concurrent.AbstractIdleService.awaitRunning(AbstractIdleService.java:160)
at org.bitcoinj.kits.WalletAppKit.launch(WalletAppKit.java:220)
at org.bitcoinj.kits.WalletAppKit.launch(WalletAppKit.java:178)
at org.bitcoinj.examples.Kit.main(Kit.java:57)
Caused by: org.bitcoinj.wallet.UnreadableWalletException: Could not parse input stream to protobuf
at org.bitcoinj.wallet.WalletProtobufSerializer.readWallet(WalletProtobufSerializer.java:455)
at org.bitcoinj.wallet.Wallet.loadFromFileStream(Wallet.java:2076)
at org.bitcoinj.wallet.Wallet.loadFromFile(Wallet.java:1961)
at org.bitcoinj.kits.WalletAppKit.loadWallet(WalletAppKit.java:508)
at org.bitcoinj.kits.WalletAppKit.createOrLoadWallet(WalletAppKit.java:480)
at org.bitcoinj.kits.WalletAppKit.startUp(WalletAppKit.java:399)
at com.google.common.util.concurrent.AbstractIdleService$DelegateService.lambda$doStart$0(AbstractIdleService.java:64)
at com.google.common.util.concurrent.Callables.lambda$threadRenaming$3(Callables.java:105)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.lang.IllegalStateException: You must construct a Context object before using bitcoinj!
at org.bitcoinj.core.Context.get(Context.java:124)
at org.bitcoinj.core.Transaction.getConfidence(Transaction.java:1586)
at org.bitcoinj.wallet.WalletProtobufSerializer.connectTransactionOutputs(WalletProtobufSerializer.java:771)
at org.bitcoinj.wallet.WalletProtobufSerializer.readWallet(WalletProtobufSerializer.java:551)
at org.bitcoinj.wallet.WalletProtobufSerializer.readWallet(WalletProtobufSerializer.java:453)
... 8 more
BitcoinNetwork network = BitcoinNetwork.TESTNET;
Context.propagate(new Context()); // 这里必须要设置,否则会出现加载钱包错误
// Initialize and start a WalletAppKit. The kit handles all the boilerplate for us and is the easiest way to get everything up and running.
// Look at the WalletAppKit documentation and its source to understand what's happening behind the scenes: https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/org/bitcoinj/kits/WalletAppKit.java
// WalletAppKit extends the Guava AbstractIdleService. Have a look at the introduction to Guava services: https://github.com/google/guava/wiki/ServiceExplained
WalletAppKit kit = WalletAppKit.launch(network, new File("."), "walletappkit-example", (k) -> {
// In case you want to connect with your local bitcoind tell the kit to connect to localhost.
// This is done automatically in reg test mode.
// k.connectToLocalHost();
try {
k.setPeerNodes(PeerAddress.simple(InetAddress.getByName("127.0.0.1"), 18333));
} catch (UnknownHostException e) {
e.printStackTrace();
}
});
2.节点连接异常
WARN [NioClientManager] [o.b.n.ConnectionHandler](ConnectionHandler.java:251) Error handling SelectionKey: java.nio.channels.CancelledKeyException
java.nio.channels.CancelledKeyException: null
at sun.nio.ch.SelectionKeyImpl.ensureValid(SelectionKeyImpl.java:73)
at sun.nio.ch.SelectionKeyImpl.readyOps(SelectionKeyImpl.java:87)
at java.nio.channels.SelectionKey.isWritable(SelectionKey.java:312)
at org.bitcoinj.net.ConnectionHandler.handleKey(ConnectionHandler.java:245)
at org.bitcoinj.net.NioClientManager.handleKey(NioClientManager.java:97)
at org.bitcoinj.net.NioClientManager.run(NioClientManager.java:133)
at com.google.common.util.concurrent.AbstractExecutionThreadService$1.lambda$doStart$1(AbstractExecutionThreadService.java:57)
at com.google.common.util.concurrent.Callables.lambda$threadRenaming$3(Callables.java:105)
at org.bitcoinj.utils.ContextPropagatingThreadFactory.lambda$newThread$0(ContextPropagatingThreadFactory.java:49)
at java.lang.Thread.run(Thread.java:750)
2024-03-21 09:56:53.609 INFO [PeerGroup Thread] [o.b.c.PeerGroup](PeerGroup.java:639) Waiting 1500 ms before next connect attempt to [127.0.0.1]:18333