static private int mapConfidenceTypeRating(TransactionConfidence.ConfidenceType type) { int rv; switch (type) { case UNKNOWN: rv = UNKNOWN_RATING; break; case DEAD: rv = DEAD_RATING; break; case IN_CONFLICT: rv = IN_CONFLICT_RATING; break; case PENDING: rv = PENDING_RATING; break; case BUILDING: rv = BUILDING_RATING; break; default: rv = UNKNOWN_RATING; break; } return rv; }
public void generateGenesisTransaction(int lockTime) { Transaction genesisTx; try { //generate genesis transaction if our proof is empty if(pm.getValidationPath().size() == 0 && wallet.getBalance(BalanceType.AVAILABLE).isGreaterThan(PSNYMVALUE)) { genesisTx = tg.generateGenesisTransaction(pm, walletFile, lockTime); //TODO register listener before sending tx out, to avoid missing a confidence change genesisTx.getConfidence().addEventListener(new Listener() { @Override public void onConfidenceChanged(TransactionConfidence arg0, ChangeReason arg1) { if (arg0.getConfidenceType() != TransactionConfidence.ConfidenceType.BUILDING) { return; } if(arg0.getDepthInBlocks() == 1) { //enough confidence, write proof message to the file system System.out.println("depth of genesis tx is now 1, consider ready for usage"); } } }); } } catch (InsufficientMoneyException e) { e.printStackTrace(); } }
private void createTransientState() { ignoreNextNewBlock = new HashSet<>(); txConfidenceListener = new TransactionConfidence.Listener() { @Override public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) { // This will run on the user code thread so we shouldn't do anything too complicated here. // We only want to queue a wallet changed event and auto-save if the number of peers announcing // the transaction has changed, as that confidence change is made by the networking code which // doesn't necessarily know at that point which wallets contain which transactions, so it's up // to us to listen for that. Other types of confidence changes (type, etc) are triggered by us, // so we'll queue up a wallet change event in other parts of the code. if (reason == ChangeReason.SEEN_PEERS) { lock.lock(); try { checkBalanceFuturesLocked(null); Transaction tx = getTransaction(confidence.getTransactionHash()); queueOnTransactionConfidenceChanged(tx); maybeQueueOnWalletChanged(); } finally { lock.unlock(); } } } }; acceptRiskyTransactions = false; }
private Wallet(Context context, KeyChainGroup keyChainGroup) { this.context = context; this.params = context.getParams(); this.keyChainGroup = checkNotNull(keyChainGroup); if (params.getId().equals(NetworkParameters.ID_UNITTESTNET)) this.keyChainGroup.setLookaheadSize(5); // Cut down excess computation for unit tests. // If this keyChainGroup was created fresh just now (new wallet), make HD so a backup can be made immediately // without having to call current/freshReceiveKey. If there are already keys in the chain of any kind then // we're probably being deserialized so leave things alone: the API user can upgrade later. if (this.keyChainGroup.numKeys() == 0) this.keyChainGroup.createAndActivateNewHDChain(); watchedScripts = Sets.newHashSet(); unspent = new HashMap<Sha256Hash, Transaction>(); spent = new HashMap<Sha256Hash, Transaction>(); pending = new HashMap<Sha256Hash, Transaction>(); dead = new HashMap<Sha256Hash, Transaction>(); transactions = new HashMap<Sha256Hash, Transaction>(); extensions = new HashMap<String, WalletExtension>(); // Use a linked hash map to ensure ordering of event listeners is correct. confidenceChanged = new LinkedHashMap<Transaction, TransactionConfidence.Listener.ChangeReason>(); signers = new ArrayList<TransactionSigner>(); addTransactionSigner(new LocalTransactionSigner()); createTransientState(); }
private void createTransientState() { ignoreNextNewBlock = new HashSet<Sha256Hash>(); txConfidenceListener = new TransactionConfidence.Listener() { @Override public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) { // This will run on the user code thread so we shouldn't do anything too complicated here. // We only want to queue a wallet changed event and auto-save if the number of peers announcing // the transaction has changed, as that confidence change is made by the networking code which // doesn't necessarily know at that point which wallets contain which transactions, so it's up // to us to listen for that. Other types of confidence changes (type, etc) are triggered by us, // so we'll queue up a wallet change event in other parts of the code. if (reason == ChangeReason.SEEN_PEERS) { lock.lock(); try { checkBalanceFuturesLocked(null); Transaction tx = getTransaction(confidence.getTransactionHash()); queueOnTransactionConfidenceChanged(tx); maybeQueueOnWalletChanged(); } finally { lock.unlock(); } } } }; acceptRiskyTransactions = false; }
@Override public int compare(final AbstractTransaction tx1, final AbstractTransaction tx2) { final boolean pending1 = tx1.getConfidenceType() == TransactionConfidence.ConfidenceType.PENDING; final boolean pending2 = tx2.getConfidenceType() == TransactionConfidence.ConfidenceType.PENDING; if (pending1 != pending2) return pending1 ? -1 : 1; // TODO use dates once implemented // final Date updateTime1 = tx1.getUpdateTime(); // final long time1 = updateTime1 != null ? updateTime1.getTime() : 0; // final Date updateTime2 = tx2.getUpdateTime(); // final long time2 = updateTime2 != null ? updateTime2.getTime() : 0; // If both not pending if (!pending1 && !pending2) { final int time1 = tx1.getAppearedAtChainHeight(); final int time2 = tx2.getAppearedAtChainHeight(); if (time1 != time2) return time1 > time2 ? -1 : 1; } return Arrays.equals(tx1.getHashBytes(),tx2.getHashBytes()) ? 1 : -1; }
private void checkTxConfirmation(HistoryTx historyTx, BitTransaction tx) { checkState(lock.isHeldByCurrentThread(), "Lock is held by another thread"); int height = historyTx.getHeight(); TransactionConfidence.ConfidenceType confidence = tx.getConfidenceType(); if (height > 0) { switch (confidence) { case BUILDING: // If the height is the same, don't do anything if (tx.getAppearedAtChainHeight() == historyTx.getHeight()) { break; } case PENDING: setAppearedAtChainHeight(tx, height, true); maybeUpdateBlockDepth(tx, true); maybeMovePool(tx); break; case DEAD: case UNKNOWN: default: throw new RuntimeException("Unsupported confidence type: " + tx.getConfidenceType().name()); } } }
private Result analyzeIsFinal() { // Transactions we create ourselves are, by definition, not at risk of double spending against us. if (tx.getConfidence().getSource() == TransactionConfidence.Source.SELF) return Result.OK; final int height = wallet.getLastBlockSeenHeight(); final long time = wallet.getLastBlockSeenTimeSecs(); // If the transaction has a lock time specified in blocks, we consider that if the tx would become final in the // next block it is not risky (as it would confirm normally). final int adjustedHeight = height + 1; if (!tx.isFinal(adjustedHeight, time)) { nonFinal = tx; return Result.NON_FINAL; } for (Transaction dep : dependencies) { if (!dep.isFinal(adjustedHeight, time)) { nonFinal = dep; return Result.NON_FINAL; } } return Result.OK; }
public void updateConfidence(TransactionConfidence.ConfidenceType confidenceType, int depthInBlocks, int numBroadcastPeers) { switch (confidenceType) { case UNKNOWN: tooltip.setText(Res.get("confidence.unknown")); txConfidenceIndicator.setProgress(0); break; case PENDING: tooltip.setText(Res.get("confidence.seen", numBroadcastPeers > -1 ? numBroadcastPeers : Res.get("shared.na"))); txConfidenceIndicator.setProgress(-1.0); break; case BUILDING: tooltip.setText(Res.get("confidence.confirmed", depthInBlocks)); txConfidenceIndicator.setProgress(Math.min(1, (double) depthInBlocks / 6.0)); break; case DEAD: tooltip.setText(Res.get("confidence.invalid")); txConfidenceIndicator.setProgress(0); break; } txConfidenceIndicator.setPrefSize(24, 24); }
private void setupConfidence(BsqWalletService bsqWalletService) { txConfidenceIndicator = new TxConfidenceIndicator(); txConfidenceIndicator.setId("funds-confidence"); Tooltip tooltip = new Tooltip(); txConfidenceIndicator.setProgress(0); txConfidenceIndicator.setPrefSize(24, 24); txConfidenceIndicator.setTooltip(tooltip); txConfidenceListener = new TxConfidenceListener(txId) { @Override public void onTransactionConfidenceChanged(TransactionConfidence confidence) { updateConfidence(confidence, tooltip); } }; bsqWalletService.addTxConfidenceListener(txConfidenceListener); updateConfidence(bsqWalletService.getConfidenceForTxId(txId), tooltip); }
public static void updateConfidence(TransactionConfidence confidence, Tooltip tooltip, TxConfidenceIndicator txConfidenceIndicator) { if (confidence != null) { switch (confidence.getConfidenceType()) { case UNKNOWN: tooltip.setText(Res.get("confidence.unknown")); txConfidenceIndicator.setProgress(0); break; case PENDING: tooltip.setText(Res.get("confidence.seen", confidence.numBroadcastPeers())); txConfidenceIndicator.setProgress(-1.0); break; case BUILDING: tooltip.setText(Res.get("confidence.confirmed", confidence.getDepthInBlocks())); txConfidenceIndicator.setProgress(Math.min(1, (double) confidence.getDepthInBlocks() / 6.0)); break; case DEAD: tooltip.setText(Res.get("confidence.invalid")); txConfidenceIndicator.setProgress(0); break; } txConfidenceIndicator.setPrefSize(24, 24); } }
public void setup(Address address, BSFormatter formatter) { this.formatter = formatter; confidenceListener = new AddressConfidenceListener(address) { @Override public void onTransactionConfidenceChanged(TransactionConfidence confidence) { updateConfidence(confidence); } }; walletService.addAddressConfidenceListener(confidenceListener); updateConfidence(walletService.getConfidenceForAddress(address)); balanceListener = new BalanceListener(address) { @Override public void onBalanceChanged(Coin balance, Transaction tx) { updateBalance(balance); } }; walletService.addBalanceListener(balanceListener); updateBalance(walletService.getBalanceForAddress(address)); }
public void setup(String txID) { if (txConfidenceListener != null) walletService.removeTxConfidenceListener(txConfidenceListener); txConfidenceListener = new TxConfidenceListener(txID) { @Override public void onTransactionConfidenceChanged(TransactionConfidence confidence) { updateConfidence(confidence); } }; walletService.addTxConfidenceListener(txConfidenceListener); updateConfidence(walletService.getConfidenceForTxId(txID)); textField.setText(txID); textField.setOnMouseClicked(mouseEvent -> openBlockExplorer(txID)); blockExplorerIcon.setOnMouseClicked(mouseEvent -> openBlockExplorer(txID)); copyIcon.setOnMouseClicked(e -> Utilities.copyToClipboard(txID)); }
private void setupConfidenceListener() { if (getDepositTx() != null) { TransactionConfidence transactionConfidence = getDepositTx().getConfidence(); if (transactionConfidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) { setConfirmedState(); } else { ListenableFuture<TransactionConfidence> future = transactionConfidence.getDepthFuture(1); Futures.addCallback(future, new FutureCallback<TransactionConfidence>() { @Override public void onSuccess(TransactionConfidence result) { setConfirmedState(); } @Override public void onFailure(@NotNull Throwable t) { t.printStackTrace(); log.error(t.getMessage()); throw new RuntimeException(t); } }); } } else { log.error("depositTx == null. That must not happen."); } }
@Override public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { /** * the {org.bitcoinj.wallet.DefaultCoinSelector} can only choose candidates if they * originated from the wallet, so this fix is so incoming tx (originated elsewhere) * could be spent if not confirmed */ tx.getConfidence().setSource(TransactionConfidence.Source.SELF); BalanceUpdater.updateBalaceNonBlocking(walletOp, wallet, new Runnable(){ @Override public void run() { notifyBalanceUpdate(wallet,tx); } }); }
@Override public void onConfidenceChanged(TransactionConfidence transactionConfidence, TransactionConfidence.Listener.ChangeReason changeReason) { if (checkAllPendingConfirmed()) { runOnUiThread(new Runnable() { @Override public void run() { setAuthorizationStatus(CONFIRMED); textVoterName.setText(getString(R.string.please_hand, preamble)); textVotingPasses.setText(getResources().getQuantityString(R.plurals.ballot_paper, votingPasses)); } }); removeAllListeners(); } }
/** * This method maps a bitcoin transaction confidence object to an object defined using swagger. * * @param confidence a bitcoinj TransactionConfidence object * @return confidence state as swagger object */ static private State mapConfidenceToState(TransactionConfidence confidence) { State result = new State(); result.setState(State.StateEnum.UNKNOWN); result.setDepthInBlocks(Integer.MIN_VALUE); if (confidence != null) { switch (confidence.getConfidenceType()) { case BUILDING: result.setState(State.StateEnum.BUILDING); result.setDepthInBlocks(confidence.getDepthInBlocks()); break; case PENDING: result.setState(State.StateEnum.PENDING); result.setDepthInBlocks(Integer.MIN_VALUE + confidence.numBroadcastPeers()); break; case DEAD: result.setState(State.StateEnum.DEAD); result.setDepthInBlocks(Integer.MIN_VALUE); break; case IN_CONFLICT: result.setState(State.StateEnum.CONFLICT); result.setDepthInBlocks(Integer.MIN_VALUE); break; case UNKNOWN: default: } } return result; }
@Override public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) { logger.info(String.format(" tx %s changed state to (%s, %d, %d) for change reason %s", confidence.getTransactionHash().toString(), confidence.getConfidenceType().toString(), confidence.numBroadcastPeers(), confidence.getDepthInBlocks(), reason.toString())); boolean refreshNeeded = false; if (lastState == null || lastMostConfidentTxHash == null) { lastState = mapConfidenceToState(confidence); lastMostConfidentTxHash = confidence.getTransactionHash(); refreshNeeded = true; } else { TransactionConfidence newMostConfidentConfidence = tryDetermineMostConfidentTransaction().getConfidence(); State newState = mapConfidenceToState(newMostConfidentConfidence); Sha256Hash newTxHash = newMostConfidentConfidence.getTransactionHash(); if (lastMostConfidentTxHash != newTxHash || statesAreDifferent(lastState, newState)) { lastMostConfidentTxHash = newTxHash; lastState = newState; refreshNeeded = true; } } if (refreshNeeded) { informStateListenersMostConfidentState(lastMostConfidentTxHash, lastState); } Transactions newTransactions = getTransactions(); if (transactionsAreDifferent(newTransactions, lastTransactions)) { lastTransactions = newTransactions; informStateListenersTransactionsChanged(lastTransactions); } }
@Override public CoinSelection select(Coin coin, List<TransactionOutput> list) { ArrayList<TransactionOutput> selected = new ArrayList<>(); long total = 0; for (TransactionOutput txOut : list) { if (TransactionConfidence.ConfidenceType.BUILDING == txOut.getParentTransaction().getConfidence().getConfidenceType()) { total += txOut.getValue().value; selected.add(txOut); } } return new CoinSelection(Coin.valueOf(total), selected); }
/** * */ @Override public List<CoinTransaction> getTransactionList() { List<CoinTransaction> transactions = new ArrayList<>(); Set<Transaction> txs = _coin.getWalletManager().wallet().getTransactions(true); for (Transaction tx : txs) { Coin amount = tx.getValue(_coin.getWalletManager().wallet()); String hash = tx.getHash().toString(); String amountStr = amount.toPlainString(); String fee = ""; String confirmationStr = "CONFIRMED"; if (tx.getFee() != null) { fee = tx.getFee().toPlainString(); } TransactionConfidence confidence = tx.getConfidence(); if (confidence.getDepthInBlocks() < 6) { confirmationStr = confidence.getDepthInBlocks() + " CONFIRMATIONS"; } TransactionConfidence.ConfidenceType cType = confidence.getConfidenceType(); CoinTransaction coinTransaction = new CoinTransaction(fee, hash, amountStr, confirmationStr, tx.getUpdateTime()); transactions.add(coinTransaction); } return transactions; }
private void informConfidenceListenersIfNotReorganizing() { if (insideReorg) return; for (Map.Entry<Transaction, TransactionConfidence.Listener.ChangeReason> entry : confidenceChanged.entrySet()) { final Transaction tx = entry.getKey(); tx.getConfidence().queueListeners(entry.getValue()); queueOnTransactionConfidenceChanged(tx); } confidenceChanged.clear(); }
/** * Subtract the supplied depth from the given transactions. */ private void subtractDepth(int depthToSubtract, Collection<Transaction> transactions) { for (Transaction tx : transactions) { if (tx.getConfidence().getConfidenceType() == ConfidenceType.BUILDING) { tx.getConfidence().setDepthInBlocks(tx.getConfidence().getDepthInBlocks() - depthToSubtract); confidenceChanged.put(tx, TransactionConfidence.Listener.ChangeReason.DEPTH); } } }
public static boolean isSelectable(Transaction tx) { // Only pick chain-included transactions, or transactions that are ours and pending. TransactionConfidence confidence = tx.getConfidence(); TransactionConfidence.ConfidenceType type = confidence.getConfidenceType(); return type.equals(TransactionConfidence.ConfidenceType.BUILDING) || type.equals(TransactionConfidence.ConfidenceType.PENDING) && confidence.getSource().equals(TransactionConfidence.Source.SELF) && // In regtest mode we expect to have only one peer, so we won't see transactions propagate. // TODO: The value 1 below dates from a time when transactions we broadcast *to* were counted, set to 0 (confidence.numBroadcastPeers() > 1 || tx.getParams().getId().equals(NetworkParameters.ID_REGTEST)); }
@Nullable private Result analyzeIsFinal() { // Transactions we create ourselves are, by definition, not at risk of double spending against us. if (tx.getConfidence().getSource() == TransactionConfidence.Source.SELF) return Result.OK; // We consider transactions that opt into replace-by-fee at risk of double spending. if (tx.isOptInFullRBF()) { nonFinal = tx; return Result.NON_FINAL; } if (wallet == null) return null; final int height = wallet.getLastBlockSeenHeight(); final long time = wallet.getLastBlockSeenTimeSecs(); // If the transaction has a lock time specified in blocks, we consider that if the tx would become final in the // next block it is not risky (as it would confirm normally). final int adjustedHeight = height + 1; if (!tx.isFinal(adjustedHeight, time)) { nonFinal = tx; return Result.NON_FINAL; } for (Transaction dep : dependencies) { if (!dep.isFinal(adjustedHeight, time)) { nonFinal = dep; return Result.NON_FINAL; } } return Result.OK; }
private void receiveATransactionAmount(Wallet wallet, Address toAddress, Coin amount) { final ListenableFuture<Coin> availFuture = wallet.getBalanceFuture(amount, Wallet.BalanceType.AVAILABLE); final ListenableFuture<Coin> estimatedFuture = wallet.getBalanceFuture(amount, Wallet.BalanceType.ESTIMATED); assertFalse(availFuture.isDone()); assertFalse(estimatedFuture.isDone()); // Send some pending coins to the wallet. Transaction t1 = sendMoneyToWallet(wallet, null, amount, toAddress); Threading.waitForUserCode(); final ListenableFuture<TransactionConfidence> depthFuture = t1.getConfidence().getDepthFuture(1); assertFalse(depthFuture.isDone()); assertEquals(ZERO, wallet.getBalance()); assertEquals(amount, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); assertFalse(availFuture.isDone()); // Our estimated balance has reached the requested level. assertTrue(estimatedFuture.isDone()); assertEquals(1, wallet.getPoolSize(Pool.PENDING)); assertEquals(0, wallet.getPoolSize(Pool.UNSPENT)); // Confirm the coins. sendMoneyToWallet(wallet, AbstractBlockChain.NewBlockType.BEST_CHAIN, t1); assertEquals("Incorrect confirmed tx balance", amount, wallet.getBalance()); assertEquals("Incorrect confirmed tx PENDING pool size", 0, wallet.getPoolSize(Pool.PENDING)); assertEquals("Incorrect confirmed tx UNSPENT pool size", 1, wallet.getPoolSize(Pool.UNSPENT)); assertEquals("Incorrect confirmed tx ALL pool size", 1, wallet.getTransactions(true).size()); Threading.waitForUserCode(); assertTrue(availFuture.isDone()); assertTrue(estimatedFuture.isDone()); assertTrue(depthFuture.isDone()); }
@Test @SuppressWarnings("deprecation") // Having a test for deprecated method getFromAddress() is no evil so we suppress the warning here. public void customTransactionSpending() throws Exception { // We'll set up a wallet that receives a coin, then sends a coin of lesser value and keeps the change. Coin v1 = valueOf(3, 0); sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, v1); assertEquals(v1, wallet.getBalance()); assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); assertEquals(1, wallet.getTransactions(true).size()); Coin v2 = valueOf(0, 50); Coin v3 = valueOf(0, 75); Coin v4 = valueOf(1, 25); Transaction t2 = new Transaction(PARAMS); t2.addOutput(v2, OTHER_ADDRESS); t2.addOutput(v3, OTHER_ADDRESS); t2.addOutput(v4, OTHER_ADDRESS); SendRequest req = SendRequest.forTx(t2); wallet.completeTx(req); // Do some basic sanity checks. assertEquals(1, t2.getInputs().size()); assertEquals(myAddress, t2.getInput(0).getScriptSig().getFromAddress(PARAMS)); assertEquals(TransactionConfidence.ConfidenceType.UNKNOWN, t2.getConfidence().getConfidenceType()); // We have NOT proven that the signature is correct! wallet.commitTx(t2); assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.PENDING)); assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.SPENT)); assertEquals(2, wallet.getTransactions(true).size()); }
private static void writeConfidence(Protos.Transaction.Builder txBuilder, TransactionConfidence confidence, Protos.TransactionConfidence.Builder confidenceBuilder) { synchronized (confidence) { confidenceBuilder.setType(Protos.TransactionConfidence.Type.valueOf(confidence.getConfidenceType().getValue())); if (confidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) { confidenceBuilder.setAppearedAtHeight(confidence.getAppearedAtChainHeight()); confidenceBuilder.setDepth(confidence.getDepthInBlocks()); } // TODO deprecate overriding transactions // if (confidence.getConfidenceType() == TransactionConfidence.ConfidenceType.DEAD) { // // Copy in the overriding transaction, if available. // // (A dead coinbase transaction has no overriding transaction). // if (confidence.getOverridingTransaction() != null) { // Sha256Hash overridingHash = confidence.getOverridingTransaction().getHash(); // confidenceBuilder.setOverridingTransaction(hashToByteString(overridingHash)); // } // } TransactionConfidence.Source source = confidence.getSource(); switch (source) { case SELF: confidenceBuilder.setSource(Protos.TransactionConfidence.Source.SOURCE_SELF); break; case NETWORK: confidenceBuilder.setSource(Protos.TransactionConfidence.Source.SOURCE_NETWORK); break; case UNKNOWN: // Fall through. default: confidenceBuilder.setSource(Protos.TransactionConfidence.Source.SOURCE_UNKNOWN); break; } } for (ListIterator<PeerAddress> it = confidence.getBroadcastBy(); it.hasNext();) { PeerAddress address = it.next(); Protos.PeerAddress proto = Protos.PeerAddress.newBuilder() .setIpAddress(ByteString.copyFrom(address.getAddr().getAddress())) .setPort(address.getPort()) .setServices(address.getServices().longValue()) .build(); confidenceBuilder.addBroadcastBy(proto); } txBuilder.setConfidence(confidenceBuilder); }
@Nullable @Override public TransactionConfidence.ConfidenceType getTxsExtendedConfidenceType(Protos.TransactionConfidence.Type type) { switch (type) { case INSTANTX_PENDING: return DashTransactionConfidenceExtension.INSTANTX_PENDING; case INSTANTX_LOCKED: return DashTransactionConfidenceExtension.INSTANTX_LOCKED; default: return null; } }
@Override public void appendToStringBuilder(StringBuilder builder, final TransactionConfidence confidence) { final TransactionConfidence.ConfidenceType confidenceType = confidence.getConfidenceType(); if (confidenceType.equals(INSTANTX_PENDING)) { builder.append("InstantX Lock Request"); } else if (confidenceType.equals(INSTANTX_LOCKED)) { builder.append("InstantX Locked"); final int chainHeight = confidence.getAppearedAtChainHeight(); if (chainHeight > 0) { builder.append(String.format("Appeared in best chain at height %d, depth %d.", chainHeight, confidence.getDepthInBlocks())); } } }
@Override public boolean isCoinsSelectableByDefault(Transaction tx) { final TransactionConfidence cnf = tx.getConfidence(); final TransactionConfidence.ConfidenceType confidenceType = cnf.getConfidenceType(); return confidenceType.equals(INSTANTX_LOCKED) || (confidenceType.equals(INSTANTX_PENDING) && (cnf.numBroadcastPeers() > 1 || CoinDefinition.REG_TEST_STANDARD.equals(tx.getParams().getStandardNetworkId()))); }
@Nullable @Override public String getConfidenceTypeName(TransactionConfidence.ConfidenceType confidenceType) { if (confidenceType.equals(INSTANTX_PENDING)) { return "INSTANTX_PENDING"; } else if (confidenceType.equals(INSTANTX_LOCKED)) { return "INSTANTX_LOCKED"; } else { return null; } }
@VisibleForTesting static void sortOutputs(ArrayList<TransactionOutput> outputs) { Collections.sort(outputs, new Comparator<TransactionOutput>() { @Override public int compare(TransactionOutput a, TransactionOutput b) { int depth1 = 0; int depth2 = 0; TransactionConfidence conf1 = a.getParentTransaction().getConfidence(); TransactionConfidence conf2 = b.getParentTransaction().getConfidence(); if (conf1.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) depth1 = conf1.getDepthInBlocks(); if (conf2.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) depth2 = conf2.getDepthInBlocks(); Coin aValue = a.getValue(); Coin bValue = b.getValue(); BigInteger aCoinDepth = BigInteger.valueOf(aValue.value).multiply(BigInteger.valueOf(depth1)); BigInteger bCoinDepth = BigInteger.valueOf(bValue.value).multiply(BigInteger.valueOf(depth2)); int c1 = bCoinDepth.compareTo(aCoinDepth); if (c1 != 0) return c1; // The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size. int c2 = bValue.compareTo(aValue); if (c2 != 0) return c2; // They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering. BigInteger aHash = a.getParentTransaction().getHash().toBigInteger(); BigInteger bHash = b.getParentTransaction().getHash().toBigInteger(); return aHash.compareTo(bHash); } }); }
public static boolean isSelectable(Transaction tx) { // Only pick chain-included transactions, or transactions that are ours and pending. TransactionConfidence confidence = tx.getConfidence(); TransactionConfidence.ConfidenceType type = confidence.getConfidenceType(); return type.equals(TransactionConfidence.ConfidenceType.BUILDING) || type.equals(TransactionConfidence.ConfidenceType.PENDING) && confidence.getSource().equals(TransactionConfidence.Source.SELF) && // In regtest mode we expect to have only one peer, so we won't see transactions propagate. // TODO: The value 1 below dates from a time when transactions we broadcast *to* were counted, set to 0 (confidence.numBroadcastPeers() > 1 || tx.getParams() == RegTestParams.get()); }