Transaction: move isMature() to Wallet.isTransactionMature()

That method is only needed in `Wallet`, so it's good to have it there.
On top of that, Wallet will be able to provide `NetworkParameters`
for a long time.
This commit is contained in:
Andreas Schildbach 2023-03-31 23:16:54 +02:00
parent a61761c5ab
commit 8b663363ef
4 changed files with 24 additions and 22 deletions

View File

@ -756,19 +756,6 @@ public class Transaction extends Message {
return inputs.size() == 1 && inputs.get(0).isCoinBase();
}
/**
* A transaction is mature if it is either a building coinbase tx that is as deep or deeper than the required coinbase depth, or a non-coinbase tx.
*/
public boolean isMature() {
if (!isCoinBase())
return true;
if (getConfidence().getConfidenceType() != ConfidenceType.BUILDING)
return false;
return getConfidence().getDepthInBlocks() >= params.getSpendableCoinbaseDepth();
}
@Override
public String toString() {
MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(this);

View File

@ -2149,6 +2149,19 @@ public class Wallet extends BaseTaggableObject
}
}
/**
* A transaction is mature if it is either a building coinbase tx that is as deep or deeper than the required coinbase depth, or a non-coinbase tx.
*/
public boolean isTransactionMature(Transaction tx) {
if (!tx.isCoinBase())
return true;
if (tx.getConfidence().getConfidenceType() != ConfidenceType.BUILDING)
return false;
return tx.getConfidence().getDepthInBlocks() >= params.getSpendableCoinbaseDepth();
}
/**
* Finds transactions in the specified candidates that double spend "tx". Not a general check, but it can work even if
* the double spent inputs are not ours.
@ -3352,7 +3365,7 @@ public class Wallet extends BaseTaggableObject
try {
LinkedList<TransactionOutput> candidates = new LinkedList<>();
for (Transaction tx : Iterables.concat(unspent.values(), pending.values())) {
if (excludeImmatureCoinbases && !tx.isMature()) continue;
if (excludeImmatureCoinbases && !isTransactionMature(tx)) continue;
for (TransactionOutput output : tx.getOutputs()) {
if (!output.isAvailableForSpending()) continue;
try {
@ -4614,7 +4627,7 @@ public class Wallet extends BaseTaggableObject
if (vUTXOProvider == null) {
candidates = myUnspents.stream()
.filter(output -> (!excludeUnsignable || canSignFor(output.getScriptPubKey())) &&
(!excludeImmatureCoinbases || Objects.requireNonNull(output.getParentTransaction()).isMature()))
(!excludeImmatureCoinbases || isTransactionMature(output.getParentTransaction())))
.collect(StreamUtils.toUnmodifiableList());
} else {
candidates = calculateAllSpendCandidatesFromUTXOProvider(excludeImmatureCoinbases);
@ -4685,7 +4698,7 @@ public class Wallet extends BaseTaggableObject
}
}
// Add change outputs. Do not try and spend coinbases that were mined too recently, the protocol forbids it.
if (!excludeImmatureCoinbases || tx.isMature()) {
if (!excludeImmatureCoinbases || isTransactionMature(tx)) {
for (TransactionOutput output : tx.getOutputs()) {
if (output.isAvailableForSpending() && output.isMine(this)) {
candidates.add(output);

View File

@ -331,7 +331,7 @@ public class BlockChainTest {
// The coinbase tx is not yet available to spend.
assertEquals(Coin.ZERO, testNetWallet.getBalance());
assertEquals(FIFTY_COINS, testNetWallet.getBalance(BalanceType.ESTIMATED));
assertFalse(coinbaseTransaction.isMature());
assertFalse(testNetWallet.isTransactionMature(coinbaseTransaction));
// Attempt to spend the coinbase - this should fail as the coinbase is not mature yet.
try {
@ -353,7 +353,7 @@ public class BlockChainTest {
assertEquals(FIFTY_COINS, testNetWallet.getBalance(BalanceType.ESTIMATED));
// The coinbase transaction is still not mature.
assertFalse(coinbaseTransaction.isMature());
assertFalse(testNetWallet.isTransactionMature(coinbaseTransaction));
// Attempt to spend the coinbase - this should fail.
try {
@ -371,7 +371,7 @@ public class BlockChainTest {
// Wallet now has the coinbase transaction available for spend.
assertEquals(FIFTY_COINS, testNetWallet.getBalance());
assertEquals(FIFTY_COINS, testNetWallet.getBalance(BalanceType.ESTIMATED));
assertTrue(coinbaseTransaction.isMature());
assertTrue(testNetWallet.isTransactionMature(coinbaseTransaction));
// Create a spend with the coinbase BTC to the address in the second wallet - this should now succeed.
Transaction coinbaseSend2 = testNetWallet.createSend(addressToSendTo, valueOf(49, 0));

View File

@ -34,6 +34,7 @@ import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.script.ScriptError;
import org.bitcoinj.script.ScriptException;
import org.bitcoinj.testing.FakeTxBuilder;
import org.bitcoinj.wallet.Wallet;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
@ -184,16 +185,17 @@ public class TransactionTest {
@Test
public void testIsMatureReturnsFalseIfTransactionIsCoinbaseAndConfidenceTypeIsNotEqualToBuilding() {
Wallet wallet = Wallet.createBasic(TESTNET);
Transaction tx = FakeTxBuilder.createFakeCoinbaseTx(TESTNET);
tx.getConfidence().setConfidenceType(ConfidenceType.UNKNOWN);
assertFalse(tx.isMature());
assertFalse(wallet.isTransactionMature(tx));
tx.getConfidence().setConfidenceType(ConfidenceType.PENDING);
assertFalse(tx.isMature());
assertFalse(wallet.isTransactionMature(tx));
tx.getConfidence().setConfidenceType(ConfidenceType.DEAD);
assertFalse(tx.isMature());
assertFalse(wallet.isTransactionMature(tx));
}
@Test