mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Merge pull request #7092 from stejbac/speed-up-vote-result-view-load
Speed up Vote Result display, cycle list item selection & JSON export
This commit is contained in:
commit
0b85e0615d
@ -48,7 +48,6 @@ import org.bitcoinj.core.InsufficientMoneyException;
|
|||||||
import org.bitcoinj.core.NetworkParameters;
|
import org.bitcoinj.core.NetworkParameters;
|
||||||
import org.bitcoinj.core.Sha256Hash;
|
import org.bitcoinj.core.Sha256Hash;
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.bitcoinj.core.TransactionConfidence;
|
|
||||||
import org.bitcoinj.core.TransactionInput;
|
import org.bitcoinj.core.TransactionInput;
|
||||||
import org.bitcoinj.core.TransactionOutPoint;
|
import org.bitcoinj.core.TransactionOutPoint;
|
||||||
import org.bitcoinj.core.TransactionOutput;
|
import org.bitcoinj.core.TransactionOutput;
|
||||||
@ -60,14 +59,12 @@ import org.bitcoinj.wallet.SendRequest;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@ -95,6 +92,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
private final DaoStateService daoStateService;
|
private final DaoStateService daoStateService;
|
||||||
private final UnconfirmedBsqChangeOutputListService unconfirmedBsqChangeOutputListService;
|
private final UnconfirmedBsqChangeOutputListService unconfirmedBsqChangeOutputListService;
|
||||||
private final List<Transaction> walletTransactions = new ArrayList<>();
|
private final List<Transaction> walletTransactions = new ArrayList<>();
|
||||||
|
private Map<String, Transaction> walletTransactionsById;
|
||||||
private final CopyOnWriteArraySet<BsqBalanceListener> bsqBalanceListeners = new CopyOnWriteArraySet<>();
|
private final CopyOnWriteArraySet<BsqBalanceListener> bsqBalanceListeners = new CopyOnWriteArraySet<>();
|
||||||
private final List<WalletTransactionsChangeListener> walletTransactionsChangeListeners = new ArrayList<>();
|
private final List<WalletTransactionsChangeListener> walletTransactionsChangeListeners = new ArrayList<>();
|
||||||
private boolean updateBsqWalletTransactionsPending;
|
private boolean updateBsqWalletTransactionsPending;
|
||||||
@ -233,7 +231,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
private void updateBsqBalance() {
|
private void updateBsqBalance() {
|
||||||
long ts = System.currentTimeMillis();
|
long ts = System.currentTimeMillis();
|
||||||
unverifiedBalance = Coin.valueOf(
|
unverifiedBalance = Coin.valueOf(
|
||||||
getTransactions(false).stream()
|
walletTransactions.stream()
|
||||||
.filter(tx -> tx.getConfidence().getConfidenceType() == PENDING)
|
.filter(tx -> tx.getConfidence().getConfidenceType() == PENDING)
|
||||||
.mapToLong(tx -> {
|
.mapToLong(tx -> {
|
||||||
// Sum up outputs into BSQ wallet and subtract the inputs using lockup or unlocking
|
// Sum up outputs into BSQ wallet and subtract the inputs using lockup or unlocking
|
||||||
@ -270,7 +268,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
.sum()
|
.sum()
|
||||||
);
|
);
|
||||||
|
|
||||||
Set<String> confirmedTxIdSet = getTransactions(false).stream()
|
Set<String> confirmedTxIdSet = walletTransactions.stream()
|
||||||
.filter(tx -> tx.getConfidence().getConfidenceType() == BUILDING)
|
.filter(tx -> tx.getConfidence().getConfidenceType() == BUILDING)
|
||||||
.map(Transaction::getTxId)
|
.map(Transaction::getTxId)
|
||||||
.map(Sha256Hash::toString)
|
.map(Sha256Hash::toString)
|
||||||
@ -343,13 +341,15 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
// BSQ TransactionOutputs and Transactions
|
// BSQ TransactionOutputs and Transactions
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// not thread safe - call only from user thread
|
||||||
public List<Transaction> getClonedWalletTransactions() {
|
public List<Transaction> getClonedWalletTransactions() {
|
||||||
return new ArrayList<>(walletTransactions);
|
return new ArrayList<>(walletTransactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// not thread safe - call only from user thread
|
||||||
public Stream<Transaction> getPendingWalletTransactionsStream() {
|
public Stream<Transaction> getPendingWalletTransactionsStream() {
|
||||||
return walletTransactions.stream()
|
return walletTransactions.stream()
|
||||||
.filter(transaction -> transaction.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.PENDING);
|
.filter(transaction -> transaction.getConfidence().getConfidenceType() == PENDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateBsqWalletTransactions() {
|
private void updateBsqWalletTransactions() {
|
||||||
@ -363,6 +363,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
UserThread.runAfter(() -> {
|
UserThread.runAfter(() -> {
|
||||||
walletTransactions.clear();
|
walletTransactions.clear();
|
||||||
walletTransactions.addAll(getTransactions(false));
|
walletTransactions.addAll(getTransactions(false));
|
||||||
|
walletTransactionsById = null;
|
||||||
walletTransactionsChangeListeners.forEach(WalletTransactionsChangeListener::onWalletTransactionsChange);
|
walletTransactionsChangeListeners.forEach(WalletTransactionsChangeListener::onWalletTransactionsChange);
|
||||||
updateBsqBalance();
|
updateBsqBalance();
|
||||||
updateBsqWalletTransactionsPending = false;
|
updateBsqWalletTransactionsPending = false;
|
||||||
@ -371,37 +372,6 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Transaction> getBsqWalletTransactions() {
|
|
||||||
return getTransactions(false).stream()
|
|
||||||
.filter(transaction -> transaction.getConfidence().getConfidenceType() == PENDING ||
|
|
||||||
daoStateService.containsTx(transaction.getTxId().toString()))
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Transaction> getUnverifiedBsqTransactions() {
|
|
||||||
Set<Transaction> bsqWalletTransactions = getBsqWalletTransactions();
|
|
||||||
Set<Transaction> walletTxs = new HashSet<>(getTransactions(false));
|
|
||||||
checkArgument(walletTxs.size() >= bsqWalletTransactions.size(),
|
|
||||||
"We cannot have more txsWithOutputsFoundInBsqTxo than walletTxs");
|
|
||||||
if (walletTxs.size() == bsqWalletTransactions.size()) {
|
|
||||||
// As expected
|
|
||||||
return new HashSet<>();
|
|
||||||
} else {
|
|
||||||
Map<String, Transaction> map = walletTxs.stream()
|
|
||||||
.collect(Collectors.toMap(t -> t.getTxId().toString(), Function.identity()));
|
|
||||||
|
|
||||||
Set<String> walletTxIds = walletTxs.stream()
|
|
||||||
.map(Transaction::getTxId).map(Sha256Hash::toString).collect(Collectors.toSet());
|
|
||||||
Set<String> bsqTxIds = bsqWalletTransactions.stream()
|
|
||||||
.map(Transaction::getTxId).map(Sha256Hash::toString).collect(Collectors.toSet());
|
|
||||||
|
|
||||||
walletTxIds.stream()
|
|
||||||
.filter(bsqTxIds::contains)
|
|
||||||
.forEach(map::remove);
|
|
||||||
return new HashSet<>(map.values());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Coin getValueSentFromMeForTransaction(Transaction transaction) throws ScriptException {
|
public Coin getValueSentFromMeForTransaction(Transaction transaction) throws ScriptException {
|
||||||
Coin result = Coin.ZERO;
|
Coin result = Coin.ZERO;
|
||||||
@ -414,7 +384,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
// We grab the parent tx of the connected output
|
// We grab the parent tx of the connected output
|
||||||
final Transaction parentTransaction = connectedOutput.getParentTransaction();
|
final Transaction parentTransaction = connectedOutput.getParentTransaction();
|
||||||
final boolean isConfirmed = parentTransaction != null &&
|
final boolean isConfirmed = parentTransaction != null &&
|
||||||
parentTransaction.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING;
|
parentTransaction.getConfidence().getConfidenceType() == BUILDING;
|
||||||
if (connectedOutput.isMineOrWatched(wallet)) {
|
if (connectedOutput.isMineOrWatched(wallet)) {
|
||||||
if (isConfirmed) {
|
if (isConfirmed) {
|
||||||
// We lookup if we have a BSQ tx matching the parent tx
|
// We lookup if we have a BSQ tx matching the parent tx
|
||||||
@ -455,7 +425,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
for (int i = 0; i < transaction.getOutputs().size(); i++) {
|
for (int i = 0; i < transaction.getOutputs().size(); i++) {
|
||||||
TransactionOutput output = transaction.getOutputs().get(i);
|
TransactionOutput output = transaction.getOutputs().get(i);
|
||||||
final boolean isConfirmed = output.getParentTransaction() != null &&
|
final boolean isConfirmed = output.getParentTransaction() != null &&
|
||||||
output.getParentTransaction().getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING;
|
output.getParentTransaction().getConfidence().getConfidenceType() == BUILDING;
|
||||||
if (output.isMineOrWatched(wallet)) {
|
if (output.isMineOrWatched(wallet)) {
|
||||||
if (isConfirmed) {
|
if (isConfirmed) {
|
||||||
if (txOptional.isPresent()) {
|
if (txOptional.isPresent()) {
|
||||||
@ -484,8 +454,13 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// not thread safe - call only from user thread
|
||||||
public Optional<Transaction> isWalletTransaction(String txId) {
|
public Optional<Transaction> isWalletTransaction(String txId) {
|
||||||
return walletTransactions.stream().filter(e -> e.getTxId().toString().equals(txId)).findAny();
|
if (walletTransactionsById == null) {
|
||||||
|
walletTransactionsById = walletTransactions.stream()
|
||||||
|
.collect(Collectors.toMap(tx -> tx.getTxId().toString(), tx -> tx));
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(walletTransactionsById.get(txId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,7 +72,6 @@ import org.bitcoinj.wallet.listeners.WalletReorganizeEventListener;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.common.collect.ImmutableMultiset;
|
import com.google.common.collect.ImmutableMultiset;
|
||||||
import com.google.common.collect.ImmutableSetMultimap;
|
import com.google.common.collect.ImmutableSetMultimap;
|
||||||
import com.google.common.collect.Multiset;
|
import com.google.common.collect.Multiset;
|
||||||
@ -88,7 +87,6 @@ import org.bouncycastle.crypto.params.KeyParameter;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
@ -107,6 +105,9 @@ import javax.annotation.Nullable;
|
|||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
import static org.bitcoinj.core.TransactionConfidence.ConfidenceType.BUILDING;
|
||||||
|
import static org.bitcoinj.core.TransactionConfidence.ConfidenceType.DEAD;
|
||||||
|
import static org.bitcoinj.core.TransactionConfidence.ConfidenceType.PENDING;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for BTC and BSQ wallet. Provides all non-trade specific functionality.
|
* Abstract base class for BTC and BSQ wallet. Provides all non-trade specific functionality.
|
||||||
@ -124,7 +125,6 @@ public abstract class WalletService {
|
|||||||
private final WalletChangeEventListener cacheInvalidationListener;
|
private final WalletChangeEventListener cacheInvalidationListener;
|
||||||
private final AtomicReference<Multiset<Address>> txOutputAddressCache = new AtomicReference<>();
|
private final AtomicReference<Multiset<Address>> txOutputAddressCache = new AtomicReference<>();
|
||||||
private final AtomicReference<SetMultimap<Address, Transaction>> addressToMatchingTxSetCache = new AtomicReference<>();
|
private final AtomicReference<SetMultimap<Address, Transaction>> addressToMatchingTxSetCache = new AtomicReference<>();
|
||||||
private final AtomicReference<Map<Sha256Hash, Transaction>> txByIdCache = new AtomicReference<>();
|
|
||||||
@Getter
|
@Getter
|
||||||
protected Wallet wallet;
|
protected Wallet wallet;
|
||||||
@Getter
|
@Getter
|
||||||
@ -150,7 +150,6 @@ public abstract class WalletService {
|
|||||||
cacheInvalidationListener = wallet -> {
|
cacheInvalidationListener = wallet -> {
|
||||||
txOutputAddressCache.set(null);
|
txOutputAddressCache.set(null);
|
||||||
addressToMatchingTxSetCache.set(null);
|
addressToMatchingTxSetCache.set(null);
|
||||||
txByIdCache.set(null);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,8 +336,9 @@ public abstract class WalletService {
|
|||||||
txIn = partialTx.getInput(index);
|
txIn = partialTx.getInput(index);
|
||||||
if (txIn.getConnectedOutput() != null) {
|
if (txIn.getConnectedOutput() != null) {
|
||||||
// If we don't have a sig we don't do the check to avoid error reports of failed sig checks
|
// If we don't have a sig we don't do the check to avoid error reports of failed sig checks
|
||||||
final List<ScriptChunk> chunks = txIn.getConnectedOutput().getScriptPubKey().getChunks();
|
List<ScriptChunk> chunks = txIn.getConnectedOutput().getScriptPubKey().getChunks();
|
||||||
if (!chunks.isEmpty() && chunks.get(0).data != null && chunks.get(0).data.length > 0) {
|
byte[] pushData;
|
||||||
|
if (!chunks.isEmpty() && (pushData = chunks.get(0).data) != null && pushData.length > 0) {
|
||||||
try {
|
try {
|
||||||
// We assume if it's already signed, it's hopefully got a SIGHASH type that will not invalidate when
|
// We assume if it's already signed, it's hopefully got a SIGHASH type that will not invalidate when
|
||||||
// we sign missing pieces (to check this would require either assuming any signatures are signing
|
// we sign missing pieces (to check this would require either assuming any signatures are signing
|
||||||
@ -460,9 +460,8 @@ public abstract class WalletService {
|
|||||||
transactionConfidenceList.addAll(transactions.stream()
|
transactionConfidenceList.addAll(transactions.stream()
|
||||||
.map(tx -> getTransactionConfidence(tx, address))
|
.map(tx -> getTransactionConfidence(tx, address))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.filter(con -> con.getConfidenceType() == TransactionConfidence.ConfidenceType.PENDING ||
|
.filter(con -> con.getConfidenceType() == PENDING ||
|
||||||
(con.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING &&
|
(con.getConfidenceType() == BUILDING && con.getAppearedAtChainHeight() > targetHeight))
|
||||||
con.getAppearedAtChainHeight() > targetHeight))
|
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
return getMostRecentConfidence(transactionConfidenceList);
|
return getMostRecentConfidence(transactionConfidenceList);
|
||||||
@ -486,23 +485,16 @@ public abstract class WalletService {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public TransactionConfidence getConfidenceForTxId(@Nullable String txId) {
|
public TransactionConfidence getConfidenceForTxId(@Nullable String txId) {
|
||||||
if (wallet != null && txId != null && !txId.isEmpty()) {
|
if (wallet != null && txId != null && !txId.isEmpty()) {
|
||||||
Transaction tx = getTxByIdMap().get(Sha256Hash.wrap(txId));
|
Sha256Hash hash = Sha256Hash.wrap(txId);
|
||||||
if (tx != null) {
|
Transaction tx = getTransaction(hash);
|
||||||
return tx.getConfidence();
|
TransactionConfidence confidence;
|
||||||
|
if (tx != null && (confidence = tx.getConfidence()).getConfidenceType() != DEAD) {
|
||||||
|
return confidence;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Sha256Hash, Transaction> getTxByIdMap() {
|
|
||||||
return txByIdCache.updateAndGet(map -> map != null ? map : computeTxByIdMap());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<Sha256Hash, Transaction> computeTxByIdMap() {
|
|
||||||
return wallet.getTransactions(false).stream()
|
|
||||||
.collect(ImmutableMap.toImmutableMap(Transaction::getTxId, tx -> tx));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private TransactionConfidence getTransactionConfidence(Transaction tx, Address address) {
|
private TransactionConfidence getTransactionConfidence(Transaction tx, Address address) {
|
||||||
List<TransactionConfidence> transactionConfidenceList = getOutputsWithConnectedOutputs(tx).stream()
|
List<TransactionConfidence> transactionConfidenceList = getOutputsWithConnectedOutputs(tx).stream()
|
||||||
@ -538,11 +530,9 @@ public abstract class WalletService {
|
|||||||
TransactionConfidence transactionConfidence = null;
|
TransactionConfidence transactionConfidence = null;
|
||||||
for (TransactionConfidence confidence : transactionConfidenceList) {
|
for (TransactionConfidence confidence : transactionConfidenceList) {
|
||||||
if (confidence != null) {
|
if (confidence != null) {
|
||||||
if (transactionConfidence == null ||
|
if (transactionConfidence == null || confidence.getConfidenceType() == PENDING ||
|
||||||
confidence.getConfidenceType().equals(TransactionConfidence.ConfidenceType.PENDING) ||
|
(confidence.getConfidenceType() == BUILDING &&
|
||||||
(confidence.getConfidenceType().equals(TransactionConfidence.ConfidenceType.BUILDING) &&
|
transactionConfidence.getConfidenceType() == BUILDING &&
|
||||||
transactionConfidence.getConfidenceType().equals(
|
|
||||||
TransactionConfidence.ConfidenceType.BUILDING) &&
|
|
||||||
confidence.getDepthInBlocks() < transactionConfidence.getDepthInBlocks())) {
|
confidence.getDepthInBlocks() < transactionConfidence.getDepthInBlocks())) {
|
||||||
transactionConfidence = confidence;
|
transactionConfidence = confidence;
|
||||||
}
|
}
|
||||||
@ -632,7 +622,7 @@ public abstract class WalletService {
|
|||||||
for (TransactionOutput transactionOutput : proposedTransaction.getOutputs()) {
|
for (TransactionOutput transactionOutput : proposedTransaction.getOutputs()) {
|
||||||
if (transactionOutput.getValue().isLessThan(Restrictions.getMinNonDustOutput())) {
|
if (transactionOutput.getValue().isLessThan(Restrictions.getMinNonDustOutput())) {
|
||||||
dust = dust.add(transactionOutput.getValue());
|
dust = dust.add(transactionOutput.getValue());
|
||||||
log.info("Dust TXO = {}", transactionOutput.toString());
|
log.info("Dust TXO = {}", transactionOutput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dust;
|
return dust;
|
||||||
@ -662,13 +652,13 @@ public abstract class WalletService {
|
|||||||
Futures.addCallback(sendResult.broadcastComplete, new FutureCallback<>() {
|
Futures.addCallback(sendResult.broadcastComplete, new FutureCallback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Transaction result) {
|
public void onSuccess(Transaction result) {
|
||||||
log.info("emptyBtcWallet onSuccess Transaction=" + result);
|
log.info("emptyBtcWallet onSuccess Transaction={}", result);
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(@NotNull Throwable t) {
|
public void onFailure(@NotNull Throwable t) {
|
||||||
log.error("emptyBtcWallet onFailure " + t.toString());
|
log.error("emptyBtcWallet onFailure " + t);
|
||||||
errorMessageHandler.handleErrorMessage(t.getMessage());
|
errorMessageHandler.handleErrorMessage(t.getMessage());
|
||||||
}
|
}
|
||||||
}, MoreExecutors.directExecutor());
|
}, MoreExecutors.directExecutor());
|
||||||
@ -688,7 +678,7 @@ public abstract class WalletService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getBestChainHeight() {
|
public int getBestChainHeight() {
|
||||||
final BlockChain chain = walletsSetup.getChain();
|
BlockChain chain = walletsSetup.getChain();
|
||||||
return isWalletReady() && chain != null ? chain.getBestChainHeight() : 0;
|
return isWalletReady() && chain != null ? chain.getBestChainHeight() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,13 +704,13 @@ public abstract class WalletService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addNewBestBlockListener(NewBestBlockListener listener) {
|
public void addNewBestBlockListener(NewBestBlockListener listener) {
|
||||||
final BlockChain chain = walletsSetup.getChain();
|
BlockChain chain = walletsSetup.getChain();
|
||||||
if (isWalletReady() && chain != null)
|
if (isWalletReady() && chain != null)
|
||||||
chain.addNewBestBlockListener(listener);
|
chain.addNewBestBlockListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeNewBestBlockListener(NewBestBlockListener listener) {
|
public void removeNewBestBlockListener(NewBestBlockListener listener) {
|
||||||
final BlockChain chain = walletsSetup.getChain();
|
BlockChain chain = walletsSetup.getChain();
|
||||||
if (isWalletReady() && chain != null)
|
if (isWalletReady() && chain != null)
|
||||||
chain.removeNewBestBlockListener(listener);
|
chain.removeNewBestBlockListener(listener);
|
||||||
}
|
}
|
||||||
@ -865,7 +855,7 @@ public abstract class WalletService {
|
|||||||
/**
|
/**
|
||||||
* @param serializedTransaction The serialized transaction to be added to the wallet
|
* @param serializedTransaction The serialized transaction to be added to the wallet
|
||||||
* @return The transaction we added to the wallet, which is different as the one we passed as argument!
|
* @return The transaction we added to the wallet, which is different as the one we passed as argument!
|
||||||
* @throws VerificationException
|
* @throws VerificationException if the transaction could not be parsed or fails sanity checks
|
||||||
*/
|
*/
|
||||||
public static Transaction maybeAddTxToWallet(byte[] serializedTransaction,
|
public static Transaction maybeAddTxToWallet(byte[] serializedTransaction,
|
||||||
Wallet wallet,
|
Wallet wallet,
|
||||||
|
@ -40,7 +40,6 @@ import org.bitcoinj.core.Coin;
|
|||||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||||
|
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.TableRow;
|
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
|
|
||||||
@ -51,18 +50,14 @@ import lombok.Getter;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class ProposalListItem {
|
public class ProposalListItem {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private EvaluatedProposal evaluatedProposal;
|
private final EvaluatedProposal evaluatedProposal;
|
||||||
@Getter
|
@Getter
|
||||||
private final Proposal proposal;
|
private final Proposal proposal;
|
||||||
private final Vote vote;
|
private final Vote vote;
|
||||||
private final boolean isMyBallotIncluded;
|
private final boolean isMyBallotIncluded;
|
||||||
private final BsqFormatter bsqFormatter;
|
private final BsqFormatter bsqFormatter;
|
||||||
|
|
||||||
private TableRow tableRow;
|
|
||||||
|
|
||||||
|
|
||||||
ProposalListItem(EvaluatedProposal evaluatedProposal, Ballot ballot, boolean isMyBallotIncluded,
|
ProposalListItem(EvaluatedProposal evaluatedProposal, Ballot ballot, boolean isMyBallotIncluded,
|
||||||
BsqFormatter bsqFormatter) {
|
BsqFormatter bsqFormatter) {
|
||||||
this.evaluatedProposal = evaluatedProposal;
|
this.evaluatedProposal = evaluatedProposal;
|
||||||
@ -104,17 +99,6 @@ public class ProposalListItem {
|
|||||||
return myVoteIcon;
|
return myVoteIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTableRow(TableRow tableRow) {
|
|
||||||
this.tableRow = tableRow;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetTableRow() {
|
|
||||||
if (tableRow != null) {
|
|
||||||
tableRow.setStyle(null);
|
|
||||||
tableRow.requestLayout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getProposalOwnerName() {
|
public String getProposalOwnerName() {
|
||||||
return evaluatedProposal.getProposal().getName();
|
return evaluatedProposal.getProposal().getName();
|
||||||
}
|
}
|
||||||
|
@ -148,6 +148,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
|
|||||||
private ProposalListItem selectedProposalListItem;
|
private ProposalListItem selectedProposalListItem;
|
||||||
private boolean isVoteIncludedInResult;
|
private boolean isVoteIncludedInResult;
|
||||||
private final Set<Cycle> cyclesAdded = new HashSet<>();
|
private final Set<Cycle> cyclesAdded = new HashSet<>();
|
||||||
|
private Map<String, Ballot> ballotByProposalTxIdMap;
|
||||||
private boolean hasCalculatedResult = false;
|
private boolean hasCalculatedResult = false;
|
||||||
|
|
||||||
|
|
||||||
@ -205,7 +206,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
|
|||||||
|
|
||||||
if (daoStateService.isParseBlockChainComplete()) {
|
if (daoStateService.isParseBlockChainComplete()) {
|
||||||
checkForResultPhase(daoStateService.getChainHeight());
|
checkForResultPhase(daoStateService.getChainHeight());
|
||||||
fillCycleList();
|
fillCycleListAndBallotMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
exportButton.setOnAction(event -> {
|
exportButton.setOnAction(event -> {
|
||||||
@ -243,7 +244,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
|
|||||||
@Override
|
@Override
|
||||||
public void onParseBlockCompleteAfterBatchProcessing(Block block) {
|
public void onParseBlockCompleteAfterBatchProcessing(Block block) {
|
||||||
checkForResultPhase(daoStateService.getChainHeight());
|
checkForResultPhase(daoStateService.getChainHeight());
|
||||||
fillCycleList();
|
fillCycleListAndBallotMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForResultPhase(int chainHeight) {
|
private void checkForResultPhase(int chainHeight) {
|
||||||
@ -283,16 +284,9 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
|
|||||||
resultsOfCycle = item.getResultsOfCycle();
|
resultsOfCycle = item.getResultsOfCycle();
|
||||||
|
|
||||||
// Check if my vote is included in result
|
// Check if my vote is included in result
|
||||||
isVoteIncludedInResult = false;
|
isVoteIncludedInResult = resultsOfCycle.getDecryptedVotesForCycle().stream()
|
||||||
resultsOfCycle.getEvaluatedProposals().forEach(evProposal -> resultsOfCycle.getDecryptedVotesForCycle()
|
.anyMatch(decryptedBallotsWithMerits -> bsqWalletService.isWalletTransaction(decryptedBallotsWithMerits
|
||||||
.forEach(decryptedBallotsWithMerits -> {
|
.getVoteRevealTxId()).isPresent());
|
||||||
// Iterate through all included votes to see if any of those are ours
|
|
||||||
if (!isVoteIncludedInResult) {
|
|
||||||
isVoteIncludedInResult = bsqWalletService.isWalletTransaction(decryptedBallotsWithMerits
|
|
||||||
.getVoteRevealTxId()).isPresent();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
maybeShowVoteResultErrors(item.getResultsOfCycle().getCycle());
|
maybeShowVoteResultErrors(item.getResultsOfCycle().getCycle());
|
||||||
createProposalsTable();
|
createProposalsTable();
|
||||||
@ -359,11 +353,8 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
|
|||||||
|
|
||||||
if (selectedProposalListItem != null) {
|
if (selectedProposalListItem != null) {
|
||||||
EvaluatedProposal evaluatedProposal = selectedProposalListItem.getEvaluatedProposal();
|
EvaluatedProposal evaluatedProposal = selectedProposalListItem.getEvaluatedProposal();
|
||||||
Optional<Ballot> optionalBallot = daoFacade.getAllValidBallots().stream()
|
Ballot ballot = ballotByProposalTxIdMap.get(evaluatedProposal.getProposalTxId());
|
||||||
.filter(ballot -> ballot.getTxId().equals(evaluatedProposal.getProposalTxId()))
|
|
||||||
.findAny();
|
|
||||||
|
|
||||||
Ballot ballot = optionalBallot.orElse(null);
|
|
||||||
voteListItemList.clear();
|
voteListItemList.clear();
|
||||||
resultsOfCycle.getEvaluatedProposals().stream()
|
resultsOfCycle.getEvaluatedProposals().stream()
|
||||||
.filter(evProposal -> evProposal.getProposal().equals(selectedProposalListItem.getEvaluatedProposal().getProposal()))
|
.filter(evProposal -> evProposal.getProposal().equals(selectedProposalListItem.getEvaluatedProposal().getProposal()))
|
||||||
@ -389,16 +380,19 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
|
|||||||
// Fill lists: Cycle
|
// Fill lists: Cycle
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void fillCycleList() {
|
private void fillCycleListAndBallotMap() {
|
||||||
// At data creation we delay a bit so that the UI has a chance to display the placeholder.
|
// At data creation we delay a bit so that the UI has a chance to display the placeholder.
|
||||||
if (cyclesAdded.isEmpty()) {
|
if (cyclesAdded.isEmpty()) {
|
||||||
UserThread.runAfter(this::doFillCycleList, 50, TimeUnit.MILLISECONDS);
|
UserThread.runAfter(this::doFillCycleListAndBallotMap, 50, TimeUnit.MILLISECONDS);
|
||||||
} else {
|
} else {
|
||||||
doFillCycleList();
|
doFillCycleListAndBallotMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doFillCycleList() {
|
private void doFillCycleListAndBallotMap() {
|
||||||
|
ballotByProposalTxIdMap = daoFacade.getAllValidBallots().stream()
|
||||||
|
.collect(Collectors.toMap(Ballot::getTxId, ballot -> ballot));
|
||||||
|
|
||||||
// Creating our data structure is a bit expensive so we ensure to only create the CycleListItems once.
|
// Creating our data structure is a bit expensive so we ensure to only create the CycleListItems once.
|
||||||
daoStateService.getCycles().stream()
|
daoStateService.getCycles().stream()
|
||||||
.filter(cycle -> !cyclesAdded.contains(cycle))
|
.filter(cycle -> !cyclesAdded.contains(cycle))
|
||||||
@ -412,7 +406,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
AtomicLong stakeAndMerit = new AtomicLong();
|
AtomicLong stakeAndMerit = new AtomicLong();
|
||||||
List<DecryptedBallotsWithMerits> decryptedVotesForCycle = daoStateService.getDecryptedBallotsWithMeritsList().stream()
|
List<DecryptedBallotsWithMerits> decryptedVotesForCycle = daoStateService.getDecryptedBallotsWithMeritsList().parallelStream()
|
||||||
.filter(decryptedBallotsWithMerits -> cycleService.isTxInCycle(cycle, decryptedBallotsWithMerits.getBlindVoteTxId()))
|
.filter(decryptedBallotsWithMerits -> cycleService.isTxInCycle(cycle, decryptedBallotsWithMerits.getBlindVoteTxId()))
|
||||||
.filter(decryptedBallotsWithMerits -> cycleService.isTxInCycle(cycle, decryptedBallotsWithMerits.getVoteRevealTxId()))
|
.filter(decryptedBallotsWithMerits -> cycleService.isTxInCycle(cycle, decryptedBallotsWithMerits.getVoteRevealTxId()))
|
||||||
.peek(decryptedBallotsWithMerits -> stakeAndMerit.getAndAdd(decryptedBallotsWithMerits.getStake() + decryptedBallotsWithMerits.getMerit(daoStateService)))
|
.peek(decryptedBallotsWithMerits -> stakeAndMerit.getAndAdd(decryptedBallotsWithMerits.getStake() + decryptedBallotsWithMerits.getMerit(daoStateService)))
|
||||||
@ -464,8 +458,6 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
|
|||||||
|
|
||||||
cyclesTableView.setItems(sortedCycleListItemList);
|
cyclesTableView.setItems(sortedCycleListItemList);
|
||||||
sortedCycleListItemList.comparatorProperty().bind(cyclesTableView.comparatorProperty());
|
sortedCycleListItemList.comparatorProperty().bind(cyclesTableView.comparatorProperty());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -495,11 +487,8 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
|
|||||||
proposalsTableView.setItems(sortedProposalList);
|
proposalsTableView.setItems(sortedProposalList);
|
||||||
sortedProposalList.comparatorProperty().bind(proposalsTableView.comparatorProperty());
|
sortedProposalList.comparatorProperty().bind(proposalsTableView.comparatorProperty());
|
||||||
|
|
||||||
proposalList.forEach(ProposalListItem::resetTableRow);
|
|
||||||
proposalList.clear();
|
proposalList.clear();
|
||||||
|
|
||||||
Map<String, Ballot> ballotByProposalTxIdMap = daoFacade.getAllValidBallots().stream()
|
|
||||||
.collect(Collectors.toMap(Ballot::getTxId, ballot -> ballot));
|
|
||||||
proposalList.setAll(resultsOfCycle.getEvaluatedProposals().stream()
|
proposalList.setAll(resultsOfCycle.getEvaluatedProposals().stream()
|
||||||
.filter(evaluatedProposal -> {
|
.filter(evaluatedProposal -> {
|
||||||
boolean containsKey = ballotByProposalTxIdMap.containsKey(evaluatedProposal.getProposalTxId());
|
boolean containsKey = ballotByProposalTxIdMap.containsKey(evaluatedProposal.getProposalTxId());
|
||||||
@ -893,6 +882,12 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
|
|||||||
cycleJson.addProperty("totalAcceptedVotes", cycleListItem.getResultsOfCycle().getNumAcceptedVotes());
|
cycleJson.addProperty("totalAcceptedVotes", cycleListItem.getResultsOfCycle().getNumAcceptedVotes());
|
||||||
cycleJson.addProperty("totalRejectedVotes", cycleListItem.getResultsOfCycle().getNumRejectedVotes());
|
cycleJson.addProperty("totalRejectedVotes", cycleListItem.getResultsOfCycle().getNumRejectedVotes());
|
||||||
|
|
||||||
|
List<DecryptedBallotsWithMerits> decryptedVotesForCycle = cycleListItem.getResultsOfCycle().getDecryptedVotesForCycle();
|
||||||
|
// Make sure the votes are sorted so we can easier compare json files from different users
|
||||||
|
decryptedVotesForCycle.sort(Comparator.comparing(DecryptedBallotsWithMerits::getBlindVoteTxId));
|
||||||
|
Map<String, Long> meritStakeMap = decryptedVotesForCycle.stream()
|
||||||
|
.collect(Collectors.toMap(DecryptedBallotsWithMerits::getBlindVoteTxId, d -> d.getMerit(daoStateService)));
|
||||||
|
|
||||||
JsonArray proposalsArray = new JsonArray();
|
JsonArray proposalsArray = new JsonArray();
|
||||||
List<EvaluatedProposal> evaluatedProposals = cycleListItem.getResultsOfCycle().getEvaluatedProposals();
|
List<EvaluatedProposal> evaluatedProposals = cycleListItem.getResultsOfCycle().getEvaluatedProposals();
|
||||||
evaluatedProposals.sort(Comparator.comparingLong(o -> o.getProposal().getCreationDate()));
|
evaluatedProposals.sort(Comparator.comparingLong(o -> o.getProposal().getCreationDate()));
|
||||||
@ -984,18 +979,15 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
|
|||||||
evaluatedProposals.stream()
|
evaluatedProposals.stream()
|
||||||
.filter(evaluatedProposal -> evaluatedProposal.getProposal().equals(proposal))
|
.filter(evaluatedProposal -> evaluatedProposal.getProposal().equals(proposal))
|
||||||
.forEach(evaluatedProposal -> {
|
.forEach(evaluatedProposal -> {
|
||||||
List<DecryptedBallotsWithMerits> decryptedVotesForCycle = cycleListItem.getResultsOfCycle().getDecryptedVotesForCycle();
|
|
||||||
// Make sure the votes are sorted so we can easier compare json files from different users
|
|
||||||
decryptedVotesForCycle.sort(Comparator.comparing(DecryptedBallotsWithMerits::getBlindVoteTxId));
|
|
||||||
decryptedVotesForCycle.forEach(decryptedBallotsWithMerits -> {
|
decryptedVotesForCycle.forEach(decryptedBallotsWithMerits -> {
|
||||||
JsonObject voteJson = new JsonObject();
|
JsonObject voteJson = new JsonObject();
|
||||||
// Domain data of decryptedBallotsWithMerits
|
// Domain data of decryptedBallotsWithMerits
|
||||||
voteJson.addProperty("hashOfBlindVoteList", Utilities.bytesAsHexString(decryptedBallotsWithMerits.getHashOfBlindVoteList()));
|
voteJson.addProperty("hashOfBlindVoteList", Utilities.bytesAsHexString(decryptedBallotsWithMerits.getHashOfBlindVoteList()));
|
||||||
voteJson.addProperty("blindVoteTxId", decryptedBallotsWithMerits.getBlindVoteTxId());
|
voteJson.addProperty("blindVoteTxId", decryptedBallotsWithMerits.getBlindVoteTxId());
|
||||||
voteJson.addProperty("voteRevealTxId", decryptedBallotsWithMerits.getVoteRevealTxId());
|
voteJson.addProperty("voteRevealTxId", decryptedBallotsWithMerits.getVoteRevealTxId());
|
||||||
voteJson.addProperty("stake", decryptedBallotsWithMerits.getStake());
|
long stake = decryptedBallotsWithMerits.getStake();
|
||||||
|
voteJson.addProperty("stake", stake);
|
||||||
voteJson.addProperty("voteWeight", decryptedBallotsWithMerits.getMerit(daoStateService));
|
voteJson.addProperty("voteWeight", stake + meritStakeMap.get(decryptedBallotsWithMerits.getBlindVoteTxId()));
|
||||||
String voteResult = decryptedBallotsWithMerits.getVote(evaluatedProp.getProposalTxId())
|
String voteResult = decryptedBallotsWithMerits.getVote(evaluatedProp.getProposalTxId())
|
||||||
.map(vote -> vote.isAccepted() ? "Accepted" : "Rejected")
|
.map(vote -> vote.isAccepted() ? "Accepted" : "Rejected")
|
||||||
.orElse("Ignored");
|
.orElse("Ignored");
|
||||||
|
Loading…
Reference in New Issue
Block a user