mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-01-18 21:32:35 +01:00
Basic support for version 2 transactions.
Rather than considering all version 2 transactions risky, we now look more closely if any of its inputs has a relative lock time. We can't check the relative locks though, because we usually don't have the spent outputs (to know when they were creted).
This commit is contained in:
parent
3061734993
commit
850f219607
@ -666,6 +666,9 @@ public class Transaction extends ChildMessage {
|
||||
}
|
||||
s.append('\n');
|
||||
}
|
||||
if (hasRelativeLockTime()) {
|
||||
s.append(" has relative lock time\n");
|
||||
}
|
||||
if (isOptInFullRBF()) {
|
||||
s.append(" opts into full replace-by-fee\n");
|
||||
}
|
||||
@ -710,6 +713,8 @@ public class Transaction extends ChildMessage {
|
||||
s.append("\n sequence:").append(Long.toHexString(in.getSequenceNumber()));
|
||||
if (in.isOptInFullRBF())
|
||||
s.append(", opts into full RBF");
|
||||
if (version >=2 && in.hasRelativeLockTime())
|
||||
s.append(", has RLT");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
s.append("[exception: ").append(e.getMessage()).append("]");
|
||||
@ -1339,7 +1344,8 @@ public class Transaction extends ChildMessage {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>A transaction is time locked if at least one of its inputs is non-final and it has a lock time</p>
|
||||
* <p>A transaction is time-locked if at least one of its inputs is non-final and it has a lock time. A transaction can
|
||||
* also have a relative lock time which this method doesn't tell. Use {@link #hasRelativeLockTime()} to find out.</p>
|
||||
*
|
||||
* <p>To check if this transaction is final at a given height and time, see {@link Transaction#isFinal(int, long)}
|
||||
* </p>
|
||||
@ -1353,6 +1359,20 @@ public class Transaction extends ChildMessage {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A transaction has a relative lock time
|
||||
* (<a href="https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki">BIP 68</a>) if it is version 2 or
|
||||
* higher and at least one of its inputs has its {@link TransactionInput.SEQUENCE_LOCKTIME_DISABLE_FLAG} cleared.
|
||||
*/
|
||||
public boolean hasRelativeLockTime() {
|
||||
if (version < 2)
|
||||
return false;
|
||||
for (TransactionInput input : getInputs())
|
||||
if (input.hasRelativeLockTime())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this transaction will opt into the
|
||||
* <a href="https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki">full replace-by-fee </a> semantics.
|
||||
|
@ -415,6 +415,14 @@ public class TransactionInput extends ChildMessage {
|
||||
return sequence < NO_SEQUENCE - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this input, if it belongs to a version 2 (or higher) transaction, has
|
||||
* <a href="https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki">relative lock-time</a> enabled.
|
||||
*/
|
||||
public boolean hasRelativeLockTime() {
|
||||
return (sequence & SEQUENCE_LOCKTIME_DISABLE_FLAG) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a connected transaction, runs the script against the connected pubkey and verifies they are correct.
|
||||
* @throws ScriptException if the script did not verify.
|
||||
|
@ -89,6 +89,13 @@ public class DefaultRiskAnalysis implements RiskAnalysis {
|
||||
return Result.NON_FINAL;
|
||||
}
|
||||
|
||||
// Relative time-locked transactions are risky too. We can't check the locks because usually we don't know the
|
||||
// spent outputs (to know when they were created).
|
||||
if (tx.hasRelativeLockTime()) {
|
||||
nonFinal = tx;
|
||||
return Result.NON_FINAL;
|
||||
}
|
||||
|
||||
if (wallet == null)
|
||||
return null;
|
||||
|
||||
@ -133,7 +140,7 @@ public class DefaultRiskAnalysis implements RiskAnalysis {
|
||||
*/
|
||||
public static RuleViolation isStandard(Transaction tx) {
|
||||
// TODO: Finish this function off.
|
||||
if (tx.getVersion() > 1 || tx.getVersion() < 1) {
|
||||
if (tx.getVersion() > 2 || tx.getVersion() < 1) {
|
||||
log.warn("TX considered non-standard due to unknown version number {}", tx.getVersion());
|
||||
return RuleViolation.VERSION;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import org.junit.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static org.bitcoinj.core.Coin.*;
|
||||
import static org.bitcoinj.script.ScriptOpCodes.*;
|
||||
import static org.junit.Assert.*;
|
||||
@ -231,4 +232,37 @@ public class DefaultRiskAnalysisTest {
|
||||
assertEquals(RiskAnalysis.Result.NON_FINAL, analysis.analyze());
|
||||
assertEquals(tx, analysis.getNonFinal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void relativeLockTime() throws Exception {
|
||||
Transaction tx = FakeTxBuilder.createFakeTx(PARAMS);
|
||||
tx.setVersion(2);
|
||||
checkState(!tx.hasRelativeLockTime());
|
||||
|
||||
tx.getInput(0).setSequenceNumber(TransactionInput.NO_SEQUENCE);
|
||||
DefaultRiskAnalysis analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx, NO_DEPS);
|
||||
assertEquals(RiskAnalysis.Result.OK, analysis.analyze());
|
||||
|
||||
tx.getInput(0).setSequenceNumber(0);
|
||||
analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx, NO_DEPS);
|
||||
assertEquals(RiskAnalysis.Result.NON_FINAL, analysis.analyze());
|
||||
assertEquals(tx, analysis.getNonFinal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transactionVersions() throws Exception {
|
||||
Transaction tx = FakeTxBuilder.createFakeTx(PARAMS);
|
||||
tx.setVersion(1);
|
||||
DefaultRiskAnalysis analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx, NO_DEPS);
|
||||
assertEquals(RiskAnalysis.Result.OK, analysis.analyze());
|
||||
|
||||
tx.setVersion(2);
|
||||
analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx, NO_DEPS);
|
||||
assertEquals(RiskAnalysis.Result.OK, analysis.analyze());
|
||||
|
||||
tx.setVersion(3);
|
||||
analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx, NO_DEPS);
|
||||
assertEquals(RiskAnalysis.Result.NON_STANDARD, analysis.analyze());
|
||||
assertEquals(tx, analysis.getNonStandard());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user