diff --git a/core/src/main/java/com/google/bitcoin/core/Transaction.java b/core/src/main/java/com/google/bitcoin/core/Transaction.java index 2c1103cc..116c2ede 100644 --- a/core/src/main/java/com/google/bitcoin/core/Transaction.java +++ b/core/src/main/java/com/google/bitcoin/core/Transaction.java @@ -23,6 +23,7 @@ import com.google.bitcoin.script.Script; import com.google.bitcoin.script.ScriptBuilder; import com.google.bitcoin.script.ScriptOpCodes; import com.google.bitcoin.utils.ExchangeRate; +import com.google.bitcoin.wallet.WalletTransaction.Pool; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.Ints; import com.google.common.primitives.Longs; @@ -250,12 +251,12 @@ public class Transaction extends ChildMessage implements Serializable { * Calculates the sum of the outputs that are sending coins to a key in the wallet. The flag controls whether to * include spent outputs or not. */ - Coin getValueSentToMe(Wallet wallet, boolean includeSpent) { + Coin getValueSentToMe(TransactionBag transactionBag, boolean includeSpent) { maybeParse(); // This is tested in WalletTest. Coin v = Coin.ZERO; for (TransactionOutput o : outputs) { - if (!o.isMineOrWatched(wallet)) continue; + if (!o.isMineOrWatched(transactionBag)) continue; if (!includeSpent && !o.isAvailableForSpending()) continue; v = v.add(o.getValue()); } @@ -266,11 +267,11 @@ public class Transaction extends ChildMessage implements Serializable { * If isSpent - check that all my outputs spent, otherwise check that there at least * one unspent. */ - boolean isConsistent(Wallet wallet, boolean isSpent) { + boolean isConsistent(TransactionBag transactionBag, boolean isSpent) { boolean isActuallySpent = true; for (TransactionOutput o : outputs) { if (o.isAvailableForSpending()) { - if (o.isMineOrWatched(wallet)) isActuallySpent = false; + if (o.isMineOrWatched(transactionBag)) isActuallySpent = false; if (o.getSpentBy() != null) { log.error("isAvailableForSpending != spentBy"); return false; @@ -288,8 +289,8 @@ public class Transaction extends ChildMessage implements Serializable { /** * Calculates the sum of the outputs that are sending coins to a key in the wallet. */ - public Coin getValueSentToMe(Wallet wallet) { - return getValueSentToMe(wallet, true); + public Coin getValueSentToMe(TransactionBag transactionBag) { + return getValueSentToMe(transactionBag, true); } /** @@ -354,18 +355,18 @@ public class Transaction extends ChildMessage implements Serializable { * * @return sum of the inputs that are spending coins with keys in the wallet */ - public Coin getValueSentFromMe(Wallet wallet) throws ScriptException { + public Coin getValueSentFromMe(TransactionBag wallet) throws ScriptException { maybeParse(); // This is tested in WalletTest. Coin v = Coin.ZERO; for (TransactionInput input : inputs) { // This input is taking value from a transaction in our wallet. To discover the value, // we must find the connected transaction. - TransactionOutput connected = input.getConnectedOutput(wallet.unspent); + TransactionOutput connected = input.getConnectedOutput(wallet.getTransactionPool(Pool.UNSPENT)); if (connected == null) - connected = input.getConnectedOutput(wallet.spent); + connected = input.getConnectedOutput(wallet.getTransactionPool(Pool.SPENT)); if (connected == null) - connected = input.getConnectedOutput(wallet.pending); + connected = input.getConnectedOutput(wallet.getTransactionPool(Pool.PENDING)); if (connected == null) continue; // The connected output may be the change to the sender of a previous input sent to this wallet. In this @@ -378,9 +379,9 @@ public class Transaction extends ChildMessage implements Serializable { } /** - * Returns the difference of {@link Transaction#getValueSentFromMe(Wallet)} and {@link Transaction#getValueSentToMe(Wallet)}. + * Returns the difference of {@link Transaction#getValueSentFromMe(TransactionBag)} and {@link Transaction#getValueSentToMe(TransactionBag)}. */ - public Coin getValue(Wallet wallet) throws ScriptException { + public Coin getValue(TransactionBag wallet) throws ScriptException { return getValueSentToMe(wallet).subtract(getValueSentFromMe(wallet)); } @@ -440,10 +441,10 @@ public class Transaction extends ChildMessage implements Serializable { * Returns false if this transaction has at least one output that is owned by the given wallet and unspent, true * otherwise. */ - public boolean isEveryOwnedOutputSpent(Wallet wallet) { + public boolean isEveryOwnedOutputSpent(TransactionBag transactionBag) { maybeParse(); for (TransactionOutput output : outputs) { - if (output.isAvailableForSpending() && output.isMineOrWatched(wallet)) + if (output.isAvailableForSpending() && output.isMineOrWatched(transactionBag)) return false; } return true; @@ -1091,15 +1092,15 @@ public class Transaction extends ChildMessage implements Serializable { * watched by a wallet, i.e., transaction outputs whose script's address is controlled by the wallet and transaction * outputs whose script is watched by the wallet.

* - * @param wallet The wallet that controls addresses and watches scripts. + * @param transactionBag The wallet that controls addresses and watches scripts. * @return linked list of outputs relevant to the wallet in this transaction */ - public List getWalletOutputs(Wallet wallet){ + public List getWalletOutputs(TransactionBag transactionBag){ maybeParse(); List walletOutputs = new LinkedList(); Coin v = Coin.ZERO; for (TransactionOutput o : outputs) { - if (!o.isMineOrWatched(wallet)) continue; + if (!o.isMineOrWatched(transactionBag)) continue; walletOutputs.add(o); } diff --git a/core/src/main/java/com/google/bitcoin/core/TransactionBag.java b/core/src/main/java/com/google/bitcoin/core/TransactionBag.java new file mode 100644 index 00000000..7c8fa137 --- /dev/null +++ b/core/src/main/java/com/google/bitcoin/core/TransactionBag.java @@ -0,0 +1,42 @@ +/** + * Copyright 2014 Giannis Dzegoutanis + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.bitcoin.core; + +import com.google.bitcoin.script.Script; +import com.google.bitcoin.wallet.WalletTransaction; + +import java.util.Map; + +/** + * This interface is used to abstract the {@link com.google.bitcoin.core.Wallet} and the {@link com.google.bitcoin.core.Transaction} + */ +public interface TransactionBag { + /** Returns true if this wallet contains a public key which hashes to the given hash. */ + public boolean isPubKeyHashMine(byte[] pubkeyHash); + + /** Returns true if this wallet is watching transactions for outputs with the script. */ + public boolean isWatchedScript(Script script); + + /** Returns true if this wallet contains a keypair with the given public key. */ + public boolean isPubKeyMine(byte[] pubkey); + + /** Returns true if this wallet knows the script corresponding to the given hash. */ + public boolean isPayToScriptHashMine(byte[] payToScriptHash); + + /** Returns transactions from a specific pool. */ + public Map getTransactionPool(WalletTransaction.Pool pool); +} diff --git a/core/src/main/java/com/google/bitcoin/core/TransactionOutput.java b/core/src/main/java/com/google/bitcoin/core/TransactionOutput.java index 07f8aa3c..39d6a983 100644 --- a/core/src/main/java/com/google/bitcoin/core/TransactionOutput.java +++ b/core/src/main/java/com/google/bitcoin/core/TransactionOutput.java @@ -310,17 +310,17 @@ public class TransactionOutput extends ChildMessage implements Serializable { /** * Returns true if this output is to a key in the wallet or to an address/script we are watching. */ - public boolean isMineOrWatched(Wallet wallet) { - return isMine(wallet) || isWatched(wallet); + public boolean isMineOrWatched(TransactionBag transactionBag) { + return isMine(transactionBag) || isWatched(transactionBag); } /** * Returns true if this output is to a key, or an address we have the keys for, in the wallet. */ - public boolean isWatched(Wallet wallet) { + public boolean isWatched(TransactionBag transactionBag) { try { Script script = getScriptPubKey(); - return wallet.isWatchedScript(script); + return transactionBag.isWatchedScript(script); } catch (ScriptException e) { // Just means we didn't understand the output of this transaction: ignore it. log.debug("Could not parse tx output script: {}", e.toString()); @@ -331,17 +331,17 @@ public class TransactionOutput extends ChildMessage implements Serializable { /** * Returns true if this output is to a key, or an address we have the keys for, in the wallet. */ - public boolean isMine(Wallet wallet) { + public boolean isMine(TransactionBag transactionBag) { try { Script script = getScriptPubKey(); if (script.isSentToRawPubKey()) { byte[] pubkey = script.getPubKey(); - return wallet.isPubKeyMine(pubkey); + return transactionBag.isPubKeyMine(pubkey); } if (script.isPayToScriptHash()) { - return wallet.isPayToScriptHashMine(script.getPubKeyHash()); + return transactionBag.isPayToScriptHashMine(script.getPubKeyHash()); } else { byte[] pubkeyHash = script.getPubKeyHash(); - return wallet.isPubKeyHashMine(pubkeyHash); + return transactionBag.isPubKeyHashMine(pubkeyHash); } } catch (ScriptException e) { // Just means we didn't understand the output of this transaction: ignore it. diff --git a/core/src/main/java/com/google/bitcoin/core/Wallet.java b/core/src/main/java/com/google/bitcoin/core/Wallet.java index 84eb5d07..de05febb 100644 --- a/core/src/main/java/com/google/bitcoin/core/Wallet.java +++ b/core/src/main/java/com/google/bitcoin/core/Wallet.java @@ -102,7 +102,7 @@ import static com.google.common.base.Preconditions.*; * {@link Wallet#autosaveToFile(java.io.File, long, java.util.concurrent.TimeUnit, com.google.bitcoin.wallet.WalletFiles.Listener)} * for more information about this.

*/ -public class Wallet extends BaseTaggableObject implements Serializable, BlockChainListener, PeerFilterProvider, KeyBag { +public class Wallet extends BaseTaggableObject implements Serializable, BlockChainListener, PeerFilterProvider, KeyBag, TransactionBag { private static final Logger log = LoggerFactory.getLogger(Wallet.class); private static final long serialVersionUID = 2L; private static final int MINIMUM_BLOOM_DATA_LENGTH = 8; @@ -829,14 +829,14 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha } } - /** - * Returns true if this wallet contains a public key which hashes to the given hash. - */ + /** {@inheritDoc} */ + @Override public boolean isPubKeyHashMine(byte[] pubkeyHash) { return findKeyFromPubHash(pubkeyHash) != null; } - /** Returns true if this wallet is watching transactions for outputs with the script. */ + /** {@inheritDoc} */ + @Override public boolean isWatchedScript(Script script) { lock.lock(); try { @@ -861,9 +861,8 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha } } - /** - * Returns true if this wallet contains a keypair with the given public key. - */ + /** {@inheritDoc} */ + @Override public boolean isPubKeyMine(byte[] pubkey) { return findKeyFromPubKey(pubkey) != null; } @@ -883,9 +882,8 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha } } - /** - * Returns true if this wallet knows the script corresponding to the given hash - */ + /** {@inheritDoc} */ + @Override public boolean isPayToScriptHashMine(byte[] payToScriptHash) { return findRedeemDataFromScriptHash(payToScriptHash) != null; } @@ -2356,6 +2354,28 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha } } + /** {@inheritDoc} */ + @Override + public Map getTransactionPool(Pool pool) { + lock.lock(); + try { + switch (pool) { + case UNSPENT: + return unspent; + case SPENT: + return spent; + case PENDING: + return pending; + case DEAD: + return dead; + default: + throw new RuntimeException("Unknown wallet transaction type " + pool); + } + } finally { + lock.unlock(); + } + } + /** * Deletes transactions which appeared above the given block height from the wallet, but does not touch the keys. * This is useful if you have some keys and wish to replay the block chain into the wallet in order to pick them up.