/** * <p>Specifies that the given {@link TransactionBroadcaster}, typically a {@link PeerGroup}, should be used for * sending transactions to the Bitcoin network by default. Some sendCoins methods let you specify a broadcaster * explicitly, in that case, they don't use this broadcaster. If null is specified then the wallet won't attempt * to broadcast transactions itself.</p> * * <p>You don't normally need to call this. A {@link PeerGroup} will automatically set itself as the wallets * broadcaster when you use {@link PeerGroup#addWallet(Wallet)}. A wallet can use the broadcaster when you ask * it to send money, but in future also at other times to implement various features that may require asynchronous * re-organisation of the wallet contents on the block chain. For instance, in future the wallet may choose to * optimise itself to reduce fees or improve privacy.</p> */ public void setTransactionBroadcaster(@Nullable org.bitcoinj.core.TransactionBroadcaster broadcaster) { Transaction[] toBroadcast = {}; lock.lock(); try { if (vTransactionBroadcaster == broadcaster) return; vTransactionBroadcaster = broadcaster; if (broadcaster == null) return; toBroadcast = pending.values().toArray(toBroadcast); } finally { lock.unlock(); } // Now use it to upload any pending transactions we have that are marked as not being seen by any peers yet. // Don't hold the wallet lock whilst doing this, so if the broadcaster accesses the wallet at some point there // is no inversion. for (Transaction tx : toBroadcast) { ConfidenceType confidenceType = tx.getConfidence().getConfidenceType(); checkState(confidenceType == ConfidenceType.PENDING || confidenceType == ConfidenceType.IN_CONFLICT, "Expected PENDING or IN_CONFLICT, was %s.", confidenceType); // Re-broadcast even if it's marked as already seen for two reasons // 1) Old wallets may have transactions marked as broadcast by 1 peer when in reality the network // never saw it, due to bugs. // 2) It can't really hurt. log.info("New broadcaster so uploading waiting tx {}", tx.getHash()); broadcaster.broadcastTransaction(tx); } }
/** * A wallet app should call this from time to time in order to let the wallet craft and send transactions needed * to re-organise coins internally. A good time to call this would be after receiving coins for an unencrypted * wallet, or after sending money for an encrypted wallet. If you have an encrypted wallet and just want to know * if some maintenance needs doing, call this method with andSend set to false and look at the returned list of * transactions. Maintenance might also include internal changes that involve some processing or work but * which don't require making transactions - these will happen automatically unless the password is required * in which case an exception will be thrown. * * @param aesKey the users password, if any. * @param signAndSend if true, send the transactions via the tx broadcaster and return them, if false just return them. * @return A list of transactions that the wallet just made/will make for internal maintenance. Might be empty. * @throws org.bitcoinj.wallet.DeterministicUpgradeRequiresPassword if key rotation requires the users password. */ public ListenableFuture<List<Transaction>> doMaintenance(@Nullable KeyParameter aesKey, boolean signAndSend) throws DeterministicUpgradeRequiresPassword { List<Transaction> txns; lock.lock(); keyChainGroupLock.lock(); try { txns = maybeRotateKeys(aesKey, signAndSend); if (!signAndSend) return Futures.immediateFuture(txns); } finally { keyChainGroupLock.unlock(); lock.unlock(); } checkState(!lock.isHeldByCurrentThread()); ArrayList<ListenableFuture<Transaction>> futures = new ArrayList<>(txns.size()); TransactionBroadcaster broadcaster = vTransactionBroadcaster; for (Transaction tx : txns) { try { final ListenableFuture<Transaction> future = broadcaster.broadcastTransaction(tx).future(); futures.add(future); Futures.addCallback(future, new FutureCallback<Transaction>() { @Override public void onSuccess(Transaction transaction) { log.info("Successfully broadcast key rotation tx: {}", transaction); } @Override public void onFailure(Throwable throwable) { log.error("Failed to broadcast key rotation tx", throwable); } }); } catch (Exception e) { log.error("Failed to broadcast rekey tx", e); } } return Futures.allAsList(futures); }
/** * A wallet app should call this from time to time in order to let the wallet craft and send transactions needed * to re-organise coins internally. A good time to call this would be after receiving coins for an unencrypted * wallet, or after sending money for an encrypted wallet. If you have an encrypted wallet and just want to know * if some maintenance needs doing, call this method with andSend set to false and look at the returned list of * transactions. Maintenance might also include internal changes that involve some processing or work but * which don't require making transactions - these will happen automatically unless the password is required * in which case an exception will be thrown. * * @param aesKey the users password, if any. * @param signAndSend if true, send the transactions via the tx broadcaster and return them, if false just return them. * @return A list of transactions that the wallet just made/will make for internal maintenance. Might be empty. * @throws org.bitcoinj.wallet.DeterministicUpgradeRequiresPassword if key rotation requires the users password. */ public ListenableFuture<List<Transaction>> doMaintenance(@Nullable KeyParameter aesKey, boolean signAndSend) throws DeterministicUpgradeRequiresPassword { List<Transaction> txns; lock.lock(); keyChainGroupLock.lock(); try { txns = maybeRotateKeys(aesKey, signAndSend); if (!signAndSend) return Futures.immediateFuture(txns); } finally { keyChainGroupLock.unlock(); lock.unlock(); } checkState(!lock.isHeldByCurrentThread()); ArrayList<ListenableFuture<Transaction>> futures = new ArrayList<ListenableFuture<Transaction>>(txns.size()); TransactionBroadcaster broadcaster = vTransactionBroadcaster; for (Transaction tx : txns) { try { final ListenableFuture<Transaction> future = broadcaster.broadcastTransaction(tx).future(); futures.add(future); Futures.addCallback(future, new FutureCallback<Transaction>() { @Override public void onSuccess(Transaction transaction) { log.info("Successfully broadcast key rotation tx: {}", transaction); } @Override public void onFailure(Throwable throwable) { log.error("Failed to broadcast key rotation tx", throwable); } }); } catch (Exception e) { log.error("Failed to broadcast rekey tx", e); } } return Futures.allAsList(futures); }
@Before public void setUp() { broadcaster = createMock(TransactionBroadcaster.class); wallet = createMock(Wallet.class); connection = createMock(PaymentChannelServer.ServerConnection.class); serverVersionCapture = new Capture<TwoWayChannelMessage>(); connection.sendToClient(capture(serverVersionCapture)); Utils.setMockClock(); }
public static RecordingPair makeRecorders(final Wallet serverWallet, final TransactionBroadcaster mockBroadcaster, int maxExpireTime) { RecordingPair pair = new RecordingPair(); pair.serverRecorder = new RecordingServerConnection(); pair.server = new PaymentChannelServer(mockBroadcaster, serverWallet, Coin.COIN, pair.serverRecorder); pair.clientRecorder = new RecordingClientConnection(maxExpireTime); return pair; }
public Wallet.SendResult broadcastTransactionFromWallet(Transaction tx) { trackedWallet.commitTx(tx); TransactionBroadcaster tb; Wallet.SendResult result = new Wallet.SendResult(); result.tx = tx; result.broadcastComplete = mPeerGroup.broadcastTransaction(tx); return result; }
/** * <p>Sends coins according to the given request, via the given {@link TransactionBroadcaster}.</p> * * <p>The returned object provides both the transaction, and a future that can be used to learn when the broadcast * is complete. Complete means, if the PeerGroup is limited to only one connection, when it was written out to * the socket. Otherwise when the transaction is written out and we heard it back from a different peer.</p> * * <p>Note that the sending transaction is committed to the wallet immediately, not when the transaction is * successfully broadcast. This means that even if the network hasn't heard about your transaction you won't be * able to spend those same coins again.</p> * * @param broadcaster the target to use for broadcast. * @param request the SendRequest that describes what to do, get one using static methods on SendRequest itself. * @return An object containing the transaction that was created, and a future for the broadcast of it. * @throws InsufficientMoneyException if the request could not be completed due to not enough balance. * @throws IllegalArgumentException if you try and complete the same SendRequest twice * @throws DustySendRequested if the resultant transaction would violate the dust rules. * @throws CouldNotAdjustDownwards if emptying the wallet was requested and the output can't be shrunk for fees without violating a protocol rule. * @throws ExceededMaxTransactionSize if the resultant transaction is too big for Bitcoin to process. * @throws MultipleOpReturnRequested if there is more than one OP_RETURN output for the resultant transaction. */ public SendResult sendCoins(TransactionBroadcaster broadcaster, SendRequest request) throws InsufficientMoneyException { // Should not be locked here, as we're going to call into the broadcaster and that might want to hold its // own lock. sendCoinsOffline handles everything that needs to be locked. checkState(!lock.isHeldByCurrentThread()); // Commit the TX to the wallet immediately so the spent coins won't be reused. // TODO: We should probably allow the request to specify tx commit only after the network has accepted it. Transaction tx = sendCoinsOffline(request); SendResult result = new SendResult(); result.tx = tx; // The tx has been committed to the pending pool by this point (via sendCoinsOffline -> commitTx), so it has // a txConfidenceListener registered. Once the tx is broadcast the peers will update the memory pool with the // count of seen peers, the memory pool will update the transaction confidence object, that will invoke the // txConfidenceListener which will in turn invoke the wallets event listener onTransactionConfidenceChanged // method. result.broadcast = broadcaster.broadcastTransaction(tx); result.broadcastComplete = result.broadcast.future(); return result; }
public static RecordingPair makeRecorders(final Wallet serverWallet, final TransactionBroadcaster mockBroadcaster) { return makeRecorders(serverWallet, mockBroadcaster, RecordingClientConnection.IGNORE_EXPIRE); }
/** * Sets up a new payment channel server which listens on the given port. * * @param broadcaster The PeerGroup on which transactions will be broadcast - should have multiple connections. * @param wallet The wallet which will be used to complete transactions * @param timeoutSeconds The read timeout between messages. This should accommodate latency and client ECDSA * signature operations. * @param minAcceptedChannelSize The minimum amount of coins clients must lock in to create a channel. Clients which * are unwilling or unable to lock in at least this value will immediately disconnect. * For this reason, a fairly conservative value (in terms of average value spent on a * channel) should generally be chosen. * @param eventHandlerFactory A factory which generates event handlers which are created for each new connection */ public PaymentChannelServerListener(TransactionBroadcaster broadcaster, Wallet wallet, final int timeoutSeconds, Coin minAcceptedChannelSize, HandlerFactory eventHandlerFactory) throws IOException { this.wallet = checkNotNull(wallet); this.broadcaster = checkNotNull(broadcaster); this.eventHandlerFactory = checkNotNull(eventHandlerFactory); this.minAcceptedChannelSize = checkNotNull(minAcceptedChannelSize); this.timeoutSeconds = timeoutSeconds; }
/** * <p>Sends coins to the given address, via the given {@link PeerGroup}. Change is returned to * {@link Wallet#currentChangeAddress()}. Note that a fee may be automatically added if one may be required for the * transaction to be confirmed.</p> * * <p>The returned object provides both the transaction, and a future that can be used to learn when the broadcast * is complete. Complete means, if the PeerGroup is limited to only one connection, when it was written out to * the socket. Otherwise when the transaction is written out and we heard it back from a different peer.</p> * * <p>Note that the sending transaction is committed to the wallet immediately, not when the transaction is * successfully broadcast. This means that even if the network hasn't heard about your transaction you won't be * able to spend those same coins again.</p> * * <p>You MUST ensure that value is not smaller than {@link Transaction#MIN_NONDUST_OUTPUT} or the transaction will * almost certainly be rejected by the network as dust.</p> * * @param broadcaster a {@link TransactionBroadcaster} to use to send the transactions out. * @param to Which address to send coins to. * @param value How much value to send. * @return An object containing the transaction that was created, and a future for the broadcast of it. * @throws InsufficientMoneyException if the request could not be completed due to not enough balance. * @throws DustySendRequested if the resultant transaction would violate the dust rules. * @throws CouldNotAdjustDownwards if emptying the wallet was requested and the output can't be shrunk for fees without violating a protocol rule. * @throws ExceededMaxTransactionSize if the resultant transaction is too big for Bitcoin to process. * @throws MultipleOpReturnRequested if there is more than one OP_RETURN output for the resultant transaction. */ public SendResult sendCoins(TransactionBroadcaster broadcaster, Address to, Coin value) throws InsufficientMoneyException { SendRequest request = SendRequest.to(to, value); return sendCoins(broadcaster, request); }
/** * Satisfies the given {@link SendRequest} using the default transaction broadcaster configured either via * {@link PeerGroup#addWallet(Wallet)} or directly with {@link #setTransactionBroadcaster(TransactionBroadcaster)}. * * @param request the SendRequest that describes what to do, get one using static methods on SendRequest itself. * @return An object containing the transaction that was created, and a future for the broadcast of it. * @throws IllegalStateException if no transaction broadcaster has been configured. * @throws InsufficientMoneyException if the request could not be completed due to not enough balance. * @throws IllegalArgumentException if you try and complete the same SendRequest twice * @throws DustySendRequested if the resultant transaction would violate the dust rules. * @throws CouldNotAdjustDownwards if emptying the wallet was requested and the output can't be shrunk for fees without violating a protocol rule. * @throws ExceededMaxTransactionSize if the resultant transaction is too big for Bitcoin to process. * @throws MultipleOpReturnRequested if there is more than one OP_RETURN output for the resultant transaction. */ public SendResult sendCoins(SendRequest request) throws InsufficientMoneyException { TransactionBroadcaster broadcaster = vTransactionBroadcaster; checkState(broadcaster != null, "No transaction broadcaster is configured"); return sendCoins(broadcaster, request); }