mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-12-26 18:16:45 +00:00
parse transactions by wallet node
This commit is contained in:
parent
d0a75fd268
commit
f88e3d4423
6 changed files with 205 additions and 68 deletions
|
@ -0,0 +1,63 @@
|
|||
package com.sparrowwallet.drongo.wallet;
|
||||
|
||||
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class BlockchainTransactionHash implements Comparable<BlockchainTransactionHash> {
|
||||
private final Sha256Hash hash;
|
||||
private final Integer height;
|
||||
private final Long fee;
|
||||
|
||||
public BlockchainTransactionHash(Sha256Hash hash) {
|
||||
this(hash, 0, 0L);
|
||||
}
|
||||
|
||||
public BlockchainTransactionHash(Sha256Hash hash, Integer height) {
|
||||
this(hash, height, 0L);
|
||||
}
|
||||
|
||||
public BlockchainTransactionHash(Sha256Hash hash, Integer height, Long fee) {
|
||||
this.hash = hash;
|
||||
this.height = height;
|
||||
this.fee = fee;
|
||||
}
|
||||
|
||||
public Sha256Hash getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public String getHashAsString() {
|
||||
return hash.toString();
|
||||
}
|
||||
|
||||
public Integer getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public Long getFee() {
|
||||
return fee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BlockchainTransactionHash that = (BlockchainTransactionHash) o;
|
||||
return hash.equals(that.hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(BlockchainTransactionHash reference) {
|
||||
return height - reference.height;
|
||||
}
|
||||
|
||||
public BlockchainTransactionHash copy() {
|
||||
return new BlockchainTransactionHash(hash, height, fee);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.sparrowwallet.drongo.wallet;
|
||||
|
||||
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class BlockchainTransactionHashIndex extends BlockchainTransactionHash {
|
||||
private final long index;
|
||||
private final BlockchainTransactionHashIndex spentBy;
|
||||
|
||||
public BlockchainTransactionHashIndex(Sha256Hash hash, Integer height, Long fee, long index) {
|
||||
this(hash, height, fee, index, null);
|
||||
}
|
||||
|
||||
public BlockchainTransactionHashIndex(Sha256Hash hash, Integer height, Long fee, long index, BlockchainTransactionHashIndex spentBy) {
|
||||
super(hash, height, fee);
|
||||
this.index = index;
|
||||
this.spentBy = spentBy;
|
||||
}
|
||||
|
||||
public long getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public boolean isSpent() {
|
||||
return spentBy != null;
|
||||
}
|
||||
|
||||
public BlockchainTransactionHashIndex getSpentBy() {
|
||||
return spentBy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
BlockchainTransactionHashIndex that = (BlockchainTransactionHashIndex) o;
|
||||
return index == that.index &&
|
||||
Objects.equals(spentBy, that.spentBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), index, spentBy);
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package com.sparrowwallet.drongo.wallet;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class TransactionReference implements Comparable<TransactionReference> {
|
||||
private final String transactionId;
|
||||
private final Integer height;
|
||||
private final Long fee;
|
||||
|
||||
public TransactionReference(String transactionId) {
|
||||
this(transactionId, 0, 0L);
|
||||
}
|
||||
|
||||
public TransactionReference(String transactionId, Integer height) {
|
||||
this(transactionId, height, 0L);
|
||||
}
|
||||
|
||||
public TransactionReference(String transactionId, Integer height, Long fee) {
|
||||
this.transactionId = transactionId;
|
||||
this.height = height;
|
||||
this.fee = fee;
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public Integer getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public Long getFee() {
|
||||
return fee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
TransactionReference that = (TransactionReference) o;
|
||||
return transactionId.equals(that.transactionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(transactionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(TransactionReference reference) {
|
||||
return height - reference.height;
|
||||
}
|
||||
|
||||
public TransactionReference copy() {
|
||||
return new TransactionReference(transactionId, height, fee);
|
||||
}
|
||||
}
|
|
@ -7,9 +7,7 @@ import com.sparrowwallet.drongo.crypto.ECKey;
|
|||
import com.sparrowwallet.drongo.crypto.Key;
|
||||
import com.sparrowwallet.drongo.policy.Policy;
|
||||
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||
import com.sparrowwallet.drongo.protocol.Script;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||
import com.sparrowwallet.drongo.protocol.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -23,7 +21,7 @@ public class Wallet {
|
|||
private Policy defaultPolicy;
|
||||
private List<Keystore> keystores = new ArrayList<>();
|
||||
private final Set<WalletNode> purposeNodes = new TreeSet<>();
|
||||
private final Map<String, Transaction> transactions = new HashMap<>();
|
||||
private final Map<Sha256Hash, Transaction> transactions = new HashMap<>();
|
||||
|
||||
public Wallet() {
|
||||
}
|
||||
|
@ -84,7 +82,7 @@ public class Wallet {
|
|||
return purposeNodes;
|
||||
}
|
||||
|
||||
public Map<String, Transaction> getTransactions() {
|
||||
public Map<Sha256Hash, Transaction> getTransactions() {
|
||||
return transactions;
|
||||
}
|
||||
|
||||
|
@ -204,6 +202,57 @@ public class Wallet {
|
|||
transactions.clear();
|
||||
}
|
||||
|
||||
public WalletNodeHistory getNodeHistory(WalletNode node) {
|
||||
Set<BlockchainTransactionHashIndex> receivedTXOs = new TreeSet<>();
|
||||
Set<BlockchainTransactionHashIndex> spentTXOs = new TreeSet<>();
|
||||
Set<BlockchainTransactionHashIndex> spendingTXIs = new TreeSet<>();
|
||||
|
||||
Script nodeScript = getOutputScript(node);
|
||||
for(BlockchainTransactionHash reference : node.getHistory()) {
|
||||
Transaction transaction = transactions.get(reference.getHash());
|
||||
if(transaction == null) {
|
||||
throw new IllegalStateException("Could not retrieve transaction for hash " + reference.getHashAsString());
|
||||
}
|
||||
|
||||
for(int inputIndex = 0; inputIndex < transaction.getInputs().size(); inputIndex++) {
|
||||
TransactionInput input = transaction.getInputs().get(inputIndex);
|
||||
Sha256Hash previousHash = input.getOutpoint().getHash();
|
||||
Transaction previousTransaction = transactions.get(previousHash);
|
||||
if(previousTransaction == null) {
|
||||
//No referenced transaction found, cannot check if spends from wallet
|
||||
//This is fine so long as all referenced transactions have been returned, in which case this refers to a transaction that does not affect this wallet
|
||||
continue;
|
||||
}
|
||||
|
||||
Optional<BlockchainTransactionHash> optionalTxHash = node.getHistory().stream().filter(txHash -> txHash.getHash().equals(previousHash)).findFirst();
|
||||
if(optionalTxHash.isEmpty()) {
|
||||
//No previous transaction history found, cannot check if spends from wallet
|
||||
//This is fine so long as all referenced transactions have been returned, in which case this refers to a transaction that does not affect this wallet node
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockchainTransactionHash spentTxHash = optionalTxHash.get();
|
||||
TransactionOutput spentOutput = previousTransaction.getOutputs().get((int)input.getOutpoint().getIndex());
|
||||
if(spentOutput.getScript().equals(nodeScript)) {
|
||||
BlockchainTransactionHashIndex spendingTXI = new BlockchainTransactionHashIndex(reference.getHash(), reference.getHeight(), reference.getFee(), inputIndex);
|
||||
spendingTXIs.add(spendingTXI);
|
||||
BlockchainTransactionHashIndex spentTXO = new BlockchainTransactionHashIndex(spentTxHash.getHash(), spentTxHash.getHeight(), spentTxHash.getFee(), input.getOutpoint().getIndex(), spendingTXI);
|
||||
spentTXOs.add(spentTXO);
|
||||
}
|
||||
}
|
||||
|
||||
for(int outputIndex = 0; outputIndex < transaction.getOutputs().size(); outputIndex++) {
|
||||
TransactionOutput output = transaction.getOutputs().get(outputIndex);
|
||||
if(output.getScript().equals(nodeScript)) {
|
||||
BlockchainTransactionHashIndex receivingTXO = new BlockchainTransactionHashIndex(reference.getHash(), reference.getHeight(), reference.getFee(), outputIndex);
|
||||
receivedTXOs.add(receivingTXO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new WalletNodeHistory(receivedTXOs, spentTXOs, spendingTXIs);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
if(policyType == null || scriptType == null || defaultPolicy == null || keystores.isEmpty()) {
|
||||
return false;
|
||||
|
@ -302,8 +351,8 @@ public class Wallet {
|
|||
for(WalletNode node : purposeNodes) {
|
||||
copy.getPurposeNodes().add(node.copy());
|
||||
}
|
||||
for(String transactionId : transactions.keySet()) {
|
||||
copy.getTransactions().put(transactionId, transactions.get(transactionId));
|
||||
for(Sha256Hash hash : transactions.keySet()) {
|
||||
copy.getTransactions().put(hash, transactions.get(hash));
|
||||
}
|
||||
|
||||
return copy;
|
||||
|
|
|
@ -14,7 +14,7 @@ public class WalletNode implements Comparable<WalletNode> {
|
|||
private String label;
|
||||
private Long amount;
|
||||
private Set<WalletNode> children = new TreeSet<>();
|
||||
private Set<TransactionReference> history = new TreeSet<>();
|
||||
private Set<BlockchainTransactionHash> history = new TreeSet<>();
|
||||
|
||||
private transient KeyPurpose keyPurpose;
|
||||
private transient int index = -1;
|
||||
|
@ -97,11 +97,11 @@ public class WalletNode implements Comparable<WalletNode> {
|
|||
this.children = children;
|
||||
}
|
||||
|
||||
public Set<TransactionReference> getHistory() {
|
||||
public Set<BlockchainTransactionHash> getHistory() {
|
||||
return history;
|
||||
}
|
||||
|
||||
public void setHistory(Set<TransactionReference> history) {
|
||||
public void setHistory(Set<BlockchainTransactionHash> history) {
|
||||
this.history = history;
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ public class WalletNode implements Comparable<WalletNode> {
|
|||
for(WalletNode child : getChildren()) {
|
||||
copy.getChildren().add(child.copy());
|
||||
}
|
||||
for(TransactionReference reference : getHistory()) {
|
||||
for(BlockchainTransactionHash reference : getHistory()) {
|
||||
copy.getHistory().add(reference.copy());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package com.sparrowwallet.drongo.wallet;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class WalletNodeHistory {
|
||||
private final Set<BlockchainTransactionHashIndex> receivedTXOs;
|
||||
private final Set<BlockchainTransactionHashIndex> spentTXOs;
|
||||
private final Set<BlockchainTransactionHashIndex> spendingTXIs;
|
||||
|
||||
public WalletNodeHistory(Set<BlockchainTransactionHashIndex> receivedTXOs, Set<BlockchainTransactionHashIndex> spentTXOs, Set<BlockchainTransactionHashIndex> spendingTXIs) {
|
||||
this.receivedTXOs = receivedTXOs;
|
||||
this.spentTXOs = spentTXOs;
|
||||
this.spendingTXIs = spendingTXIs;
|
||||
}
|
||||
|
||||
public Set<BlockchainTransactionHashIndex> getReceivedTXOs() {
|
||||
return receivedTXOs;
|
||||
}
|
||||
|
||||
public Set<BlockchainTransactionHashIndex> getSpentTXOs() {
|
||||
return spentTXOs;
|
||||
}
|
||||
|
||||
public Set<BlockchainTransactionHashIndex> getSpendingTXIs() {
|
||||
return spendingTXIs;
|
||||
}
|
||||
|
||||
public Set<BlockchainTransactionHashIndex> getUnspentTXOs() {
|
||||
Set<BlockchainTransactionHashIndex> unspentTXOs = new TreeSet<>(receivedTXOs);
|
||||
unspentTXOs.removeAll(spentTXOs);
|
||||
|
||||
return unspentTXOs;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue