mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-12 02:05:53 +00:00
More Wallet consistency checks
This commit is contained in:
parent
a0da0c548f
commit
6a82462d2d
@ -183,6 +183,29 @@ public class Transaction extends ChildMessage implements Serializable {
|
|||||||
return v;
|
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.
|
* Calculates the sum of the outputs that are sending coins to a key in the wallet.
|
||||||
*/
|
*/
|
||||||
|
@ -208,18 +208,48 @@ public class Wallet implements Serializable {
|
|||||||
return loadFromFileStream(new FileInputStream(f));
|
return loadFromFileStream(new FileInputStream(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isConsistent() {
|
public boolean isConsistent() {
|
||||||
|
boolean success = true;
|
||||||
// Pending and inactive can overlap, so merge them before counting
|
// Pending and inactive can overlap, so merge them before counting
|
||||||
HashSet<Transaction> pendingInactive = new HashSet<Transaction>();
|
HashSet<Transaction> pendingInactive = new HashSet<Transaction>();
|
||||||
pendingInactive.addAll(pending.values());
|
pendingInactive.addAll(pending.values());
|
||||||
pendingInactive.addAll(inactive.values());
|
pendingInactive.addAll(inactive.values());
|
||||||
|
|
||||||
int size1 = getTransactions(true, true).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();
|
int size2 = unspent.size() + spent.size() + pendingInactive.size() + dead.size();
|
||||||
if (size1 != size2) {
|
if (size1 != size2) {
|
||||||
log.error("Inconsistent wallet sizes: {} {}", size1, size2);
|
log.error("Inconsistent wallet sizes: {} {}", size1, size2);
|
||||||
|
success = true;
|
||||||
}
|
}
|
||||||
return size1 == size2;
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -232,19 +262,26 @@ public class Wallet implements Serializable {
|
|||||||
boolean serialization = stream.read() == 0xac && stream.read() == 0xed;
|
boolean serialization = stream.read() == 0xac && stream.read() == 0xed;
|
||||||
stream.reset();
|
stream.reset();
|
||||||
|
|
||||||
|
Wallet wallet;
|
||||||
|
|
||||||
if (serialization) {
|
if (serialization) {
|
||||||
ObjectInputStream ois = null;
|
ObjectInputStream ois = null;
|
||||||
try {
|
try {
|
||||||
ois = new ObjectInputStream(stream);
|
ois = new ObjectInputStream(stream);
|
||||||
return (Wallet) ois.readObject();
|
wallet = (Wallet) ois.readObject();
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
} finally {
|
} finally {
|
||||||
if (ois != null) ois.close();
|
if (ois != null) ois.close();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return WalletProtobufSerializer.readWallet(stream);
|
wallet = WalletProtobufSerializer.readWallet(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wallet.isConsistent()) {
|
||||||
|
log.error("Loaded an inconsistent wallet");
|
||||||
|
}
|
||||||
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
@ -301,10 +301,20 @@ public class WalletTool {
|
|||||||
send(outputFlag.values(options));
|
send(outputFlag.values(options));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wallet.isConsistent()) {
|
||||||
|
System.err.println("************** WALLET IS INCONSISTENT *****************");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
saveWallet(walletFile);
|
saveWallet(walletFile);
|
||||||
|
|
||||||
if (options.has(waitForFlag)) {
|
if (options.has(waitForFlag)) {
|
||||||
wait(waitForFlag.value(options));
|
wait(waitForFlag.value(options));
|
||||||
|
if (!wallet.isConsistent()) {
|
||||||
|
System.err.println("************** WALLET IS INCONSISTENT *****************");
|
||||||
|
return;
|
||||||
|
}
|
||||||
saveWallet(walletFile);
|
saveWallet(walletFile);
|
||||||
} else {
|
} else {
|
||||||
shutdown();
|
shutdown();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user