Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Index: tests/com/google/bitcoin/core/WalletTest.java
- IDEA additional info:
- Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
- <+>UTF-8
- ===================================================================
- --- tests/com/google/bitcoin/core/WalletTest.java (revision b43b68626432650e94ffa680bbaf980589f8e3ec)
- +++ tests/com/google/bitcoin/core/WalletTest.java (revision )
- @@ -86,6 +86,43 @@
- }
- @Test
- + public void customTransactionSpending() throws Exception {
- + // We'll set up a wallet that receives a coin, then sends a coin of lesser value and keeps the change.
- + BigInteger v1 = Utils.toNanoCoins(3, 0);
- + Transaction t1 = createFakeTx(params, v1, myAddress);
- +
- + wallet.receiveFromBlock(t1, null, BlockChain.NewBlockType.BEST_CHAIN);
- + assertEquals(v1, wallet.getBalance());
- + assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
- + assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.ALL));
- +
- + ECKey k2 = new ECKey();
- + Address a2 = k2.toAddress(params);
- + BigInteger v2 = toNanoCoins(0, 50);
- + BigInteger v3 = toNanoCoins(0, 75);
- + BigInteger v4 = toNanoCoins(1, 25);
- +
- + Transaction t2 = new Transaction(params);
- + t2.addOutput(v2, a2);
- + t2.addOutput(v3, a2);
- + t2.addOutput(v4, a2);
- + boolean complete = wallet.completeTx(t2);
- +
- + // Do some basic sanity checks.
- + assertTrue(complete);
- + assertEquals(1, t2.getInputs().size());
- + assertEquals(myAddress, t2.getInputs().get(0).getScriptSig().getFromAddress());
- + assertEquals(t2.getConfidence().getConfidenceType(), TransactionConfidence.ConfidenceType.NOT_SEEN_IN_CHAIN);
- +
- + // We have NOT proven that the signature is correct!
- +
- + wallet.commitTx(t2);
- + assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.PENDING));
- + assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.SPENT));
- + assertEquals(2, wallet.getPoolSize(WalletTransaction.Pool.ALL));
- + }
- +
- + @Test
- public void sideChain() throws Exception {
- // The wallet receives a coin on the main chain, then on a side chain. Only main chain counts towards balance.
- BigInteger v1 = Utils.toNanoCoins(1, 0);
- Index: src/com/google/bitcoin/core/Transaction.java
- IDEA additional info:
- Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
- <+>UTF-8
- ===================================================================
- --- src/com/google/bitcoin/core/Transaction.java (revision b43b68626432650e94ffa680bbaf980589f8e3ec)
- +++ src/com/google/bitcoin/core/Transaction.java (revision )
- @@ -559,6 +559,13 @@
- }
- /**
- + * Creates an output based on the given address and value, adds it to this transaction.
- + */
- + public void addOutput(BigInteger value, Address address) {
- + addOutput(new TransactionOutput(params, this, value, address));
- + }
- +
- + /**
- * Once a transaction has some inputs and outputs added, the signatures in the inputs can be calculated. The
- * signature is over the transaction itself, to prove the redeemer actually created that transaction,
- * so we have to do this step last.<p>
- Index: src/com/google/bitcoin/core/Wallet.java
- IDEA additional info:
- Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
- <+>UTF-8
- ===================================================================
- --- src/com/google/bitcoin/core/Wallet.java (revision b43b68626432650e94ffa680bbaf980589f8e3ec)
- +++ src/com/google/bitcoin/core/Wallet.java (revision )
- @@ -679,7 +679,7 @@
- * and we did not create it, and it spends some of our outputs.</li>
- * </ol>
- */
- - synchronized void commitTx(Transaction tx) throws VerificationException {
- + public synchronized void commitTx(Transaction tx) throws VerificationException {
- assert !pending.containsKey(tx.getHash()) : "commitTx called on the same transaction twice";
- log.info("commitTx of {}", tx.getHashAsString());
- tx.updatedAt = Utils.now();
- @@ -884,18 +884,14 @@
- /**
- * Statelessly creates a transaction that sends the given number of nanocoins to address. The change is sent to
- - * the first address in the wallet, so you must have added at least one key.<p>
- + * {@link Wallet#getChangeAddress()}, so you must have added at least one key.<p>
- * <p/>
- * This method is stateless in the sense that calling it twice with the same inputs will result in two
- * Transaction objects which are equal. The wallet is not updated to track its pending status or to mark the
- * coins as spent until commitTx is called on the result.
- */
- synchronized Transaction createSend(Address address, BigInteger nanocoins) {
- - // For now let's just pick the first key in our keychain. In future we might want to do something else to
- - // give the user better privacy here, eg in incognito mode.
- - assert keychain.size() > 0 : "Can't send value without an address to use for receiving change";
- - ECKey first = keychain.get(0);
- - return createSend(address, nanocoins, first.toAddress(params));
- + return createSend(address, nanocoins, getChangeAddress());
- }
- /**
- @@ -920,8 +916,8 @@
- }
- /**
- - * Sends coins to the given address, via the given {@link PeerGroup}. Change is returned to the first key in the
- - * wallet. The transaction will be announced to any connected nodes asynchronously. If you would like to know when
- + * Sends coins to the given address, via the given {@link PeerGroup}. Change is returned to {@link Wallet#getChangeAddress()}.
- + * The transaction will be announced to any connected nodes asynchronously. If you would like to know when
- * the transaction was successfully sent to at least one node, use
- * {@link Wallet#sendCoinsOffline(Address, java.math.BigInteger)} and then {@link PeerGroup#broadcastTransaction(Transaction)}
- * on the result to obtain a {@link java.util.concurrent.Future<Transaction>}.
- @@ -941,8 +937,8 @@
- }
- /**
- - * Sends coins to the given address, via the given {@link PeerGroup}. Change is returned to the first key in the
- - * wallet. The method will block until the transaction has been announced to at least one node.
- + * Sends coins to the given address, via the given {@link PeerGroup}. Change is returned to {@link Wallet#getChangeAddress()}.
- + * The method will block until the transaction has been announced to at least one node.
- *
- * @param peerGroup a PeerGroup to use for broadcast or null.
- * @param to Which address to send coins to.
- @@ -961,7 +957,7 @@
- }
- /**
- - * Sends coins to the given address, via the given {@link Peer}. Change is returned to the first key in the wallet.
- + * Sends coins to the given address, via the given {@link Peer}. Change is returned to {@link Wallet#getChangeAddress()}.
- * If an exception is thrown by {@link Peer#sendMessage(Message)} the transaction is still committed, so the
- * pending transaction must be broadcast <b>by you</b> at some other time.
- *
- @@ -1004,6 +1000,33 @@
- synchronized Transaction createSend(Address address, BigInteger nanocoins, Address changeAddress) {
- log.info("Creating send tx to " + address.toString() + " for " +
- bitcoinValueToFriendlyString(nanocoins));
- +
- + Transaction sendTx = new Transaction(params);
- + sendTx.addOutput(nanocoins, address);
- +
- + if (completeTx(sendTx, changeAddress)) {
- + return sendTx;
- + } else {
- + return null;
- + }
- + }
- +
- + /**
- + * Takes a transaction with arbitrary outputs, gathers the necessary inputs for spending, and signs it
- + * @param sendTx The transaction to complete
- + * @param changeAddress Which address to send the change to, in case we can't make exactly the right value from
- + * our coins. This should be an address we own (is in the keychain).
- + * @return False if we cannot afford this send, true otherwise
- + */
- + public synchronized boolean completeTx(Transaction sendTx, Address changeAddress) {
- + // Calculate the transaction total
- + BigInteger nanocoins = BigInteger.ZERO;
- + for(TransactionOutput output : sendTx.getOutputs()) {
- + nanocoins = nanocoins.add(output.getValue());
- + }
- +
- + log.info("Completing send tx with {} outputs totalling {}", sendTx.getOutputs().size(), bitcoinValueToFriendlyString(nanocoins));
- +
- // To send money to somebody else, we need to do gather up transactions with unspent outputs until we have
- // sufficient value. Many coin selection algorithms are possible, we use a simple but suboptimal one.
- // TODO: Sort coins so we use the smallest first, to combat wallet fragmentation and reduce fees.
- @@ -1023,12 +1046,10 @@
- log.info("Insufficient value in wallet for send, missing " +
- bitcoinValueToFriendlyString(nanocoins.subtract(valueGathered)));
- // TODO: Should throw an exception here.
- - return null;
- + return false;
- }
- assert gathered.size() > 0;
- - Transaction sendTx = new Transaction(params);
- sendTx.getConfidence().setConfidenceType(TransactionConfidence.ConfidenceType.NOT_SEEN_IN_CHAIN);
- - sendTx.addOutput(new TransactionOutput(params, sendTx, nanocoins, address));
- BigInteger change = valueGathered.subtract(nanocoins);
- if (change.compareTo(BigInteger.ZERO) > 0) {
- // The value of the inputs is greater than what we want to send. Just like in real life then,
- @@ -1049,8 +1070,26 @@
- // happen, if it does it means the wallet has got into an inconsistent state.
- throw new RuntimeException(e);
- }
- - log.info(" created {}", sendTx.getHashAsString());
- - return sendTx;
- + log.info(" completed {}", sendTx.getHashAsString());
- + return true;
- + }
- +
- + /**
- + * Takes a transaction with arbitrary outputs, gathers the necessary inputs for spending, and signs it.
- + * Change goes to {@link Wallet#getChangeAddress()}
- + * @param sendTx The transaction to complete
- + * @return False if we cannot afford this send, true otherwise
- + */
- + public synchronized boolean completeTx(Transaction sendTx) {
- + return completeTx(sendTx, getChangeAddress());
- + }
- +
- + synchronized Address getChangeAddress() {
- + // For now let's just pick the first key in our keychain. In future we might want to do something else to
- + // give the user better privacy here, eg in incognito mode.
- + assert keychain.size() > 0 : "Can't send value without an address to use for receiving change";
- + ECKey first = keychain.get(0);
- + return first.toAddress(params);
- }
- /**
Advertisement
Add Comment
Please, Sign In to add comment