More Wallet consistency checks

Conflicts:

	src/com/google/bitcoin/core/Wallet.java
	tools/src/main/java/com/google/bitcoin/tools/WalletTool.java
This commit is contained in:
Miron Cuperman 2012-04-09 19:06:16 -07:00
parent 807914b9fd
commit fa87176f62
2 changed files with 66 additions and 4 deletions

View File

@ -181,6 +181,29 @@ public class Transaction extends ChildMessage implements Serializable {
}
return v;
}
/*
* If isSpent - check that all my outputs spent, otherwise check that there at least
* one unspent.
*/
boolean isConsistent(Wallet wallet, boolean isSpent) {
boolean isActuallySpent = true;
for (TransactionOutput o : outputs) {
if (o.isAvailableForSpending()) {
if (o.isMine(wallet)) isActuallySpent = false;
if (o.getSpentBy() != null) {
log.error("isAvailableForSpending != spentBy");
return false;
}
} else {
if (o.getSpentBy() == null) {
log.error("isAvailableForSpending != spentBy");
return false;
}
}
}
return isActuallySpent == isSpent;
}
/**
* Calculates the sum of the outputs that are sending coins to a key in the wallet.

View File

@ -206,29 +206,68 @@ public class Wallet implements Serializable {
return loadFromFileStream(new FileInputStream(f));
}
private boolean isConsistent() {
public boolean isConsistent() {
boolean success = true;
// Pending and inactive can overlap, so merge them before counting
HashSet<Transaction> pendingInactive = new HashSet<Transaction>();
pendingInactive.addAll(pending.values());
pendingInactive.addAll(inactive.values());
return getTransactions(true, true).size() ==
unspent.size() + spent.size() + pendingInactive.size() + dead.size();
Set<Transaction> transactions = getTransactions(true, true);
Set<Sha256Hash> hashes = new HashSet<Sha256Hash>();
for (Transaction tx : transactions) {
hashes.add(tx.getHash());
}
int size1 = transactions.size();
if (size1 != hashes.size()) {
log.error("Two transactions with same hash");
success = false;
}
int size2 = unspent.size() + spent.size() + pendingInactive.size() + dead.size();
if (size1 != size2) {
log.error("Inconsistent wallet sizes: {} {}", size1, size2);
success = true;
}
for (Transaction tx : unspent.values()) {
if (!tx.isConsistent(this, false)) {
success = false;
log.error("Inconsistent unspent tx {}", tx.getHashAsString());
}
}
for (Transaction tx : spent.values()) {
if (!tx.isConsistent(this, true)) {
success = false;
log.error("Inconsistent spent tx {}", tx.getHashAsString());
}
}
return success;
}
/**
* Returns a wallet deserialized from the given input stream.
*/
public static Wallet loadFromFileStream(InputStream f) throws IOException {
Wallet wallet;
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(f);
return (Wallet) ois.readObject();
wallet = (Wallet) ois.readObject();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} finally {
if (ois != null) ois.close();
}
if (!wallet.isConsistent())
log.error("Loaded an inconsistent wallet");
return wallet;
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {