3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-14 11:15:51 +00:00

Separate Transaction and Wallet classes

This commit is contained in:
Giannis Dzegoutanis 2014-09-23 21:53:20 +03:00 committed by Mike Hearn
parent 014f6ff22c
commit 48de05ac0f
4 changed files with 99 additions and 36 deletions

View File

@ -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.</p>
*
* @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<TransactionOutput> getWalletOutputs(Wallet wallet){
public List<TransactionOutput> getWalletOutputs(TransactionBag transactionBag){
maybeParse();
List<TransactionOutput> walletOutputs = new LinkedList<TransactionOutput>();
Coin v = Coin.ZERO;
for (TransactionOutput o : outputs) {
if (!o.isMineOrWatched(wallet)) continue;
if (!o.isMineOrWatched(transactionBag)) continue;
walletOutputs.add(o);
}

View File

@ -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<Sha256Hash, Transaction> getTransactionPool(WalletTransaction.Pool pool);
}

View File

@ -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.

View File

@ -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.</p>
*/
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<Sha256Hash, Transaction> 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.