mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-13 10:45:51 +00:00
Be aware of opt-in full replace-by-fee.
This commit is contained in:
parent
ee1aa05460
commit
786a11187e
@ -24,6 +24,8 @@ import org.bitcoinj.script.ScriptBuilder;
|
||||
import org.bitcoinj.script.ScriptOpCodes;
|
||||
import org.bitcoinj.utils.ExchangeRate;
|
||||
import org.bitcoinj.wallet.WalletTransaction.Pool;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
@ -641,6 +643,9 @@ public class Transaction extends ChildMessage {
|
||||
}
|
||||
s.append(String.format(Locale.US, " time locked until %s%n", time));
|
||||
}
|
||||
if (isOptInFullRBF()) {
|
||||
s.append(" opts into full replace-by-fee%n");
|
||||
}
|
||||
if (inputs.size() == 0) {
|
||||
s.append(String.format(Locale.US, " INCOMPLETE: No inputs!%n"));
|
||||
return s.toString();
|
||||
@ -680,6 +685,10 @@ public class Transaction extends ChildMessage {
|
||||
s.append(Utils.HEX.encode(scriptPubKey.getPubKeyHash()));
|
||||
}
|
||||
}
|
||||
String flags = Joiner.on(", ").skipNulls().join(in.hasSequence() ? "has sequence" : null,
|
||||
in.isOptInFullRBF() ? "opts into full RBF" : null);
|
||||
if (!flags.isEmpty())
|
||||
s.append("\n (").append(flags).append(')');
|
||||
} catch (Exception e) {
|
||||
s.append("[exception: ").append(e.getMessage()).append("]");
|
||||
}
|
||||
@ -1281,6 +1290,17 @@ public class Transaction extends ChildMessage {
|
||||
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.
|
||||
*/
|
||||
public boolean isOptInFullRBF() {
|
||||
for (TransactionInput input : getInputs())
|
||||
if (input.isOptInFullRBF())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns true if this transaction is considered finalized and can be placed in a block. Non-finalized
|
||||
* transactions won't be included by miners and can be replaced with newer versions using sequence numbers.
|
||||
|
@ -21,6 +21,8 @@ import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.wallet.DefaultRiskAnalysis;
|
||||
import org.bitcoinj.wallet.KeyBag;
|
||||
import org.bitcoinj.wallet.RedeemData;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -46,7 +48,7 @@ public class TransactionInput extends ChildMessage {
|
||||
// Magic outpoint index that indicates the input is in fact unconnected.
|
||||
private static final long UNCONNECTED = 0xFFFFFFFFL;
|
||||
|
||||
// Allows for altering transactions after they were broadcast.
|
||||
// Allows for altering transactions after they were broadcast. Values below NO_SEQUENCE-1 mean it can be altered.
|
||||
private long sequence;
|
||||
// Data needed to connect to the output of the transaction we're gathering coins from.
|
||||
private TransactionOutPoint outpoint;
|
||||
@ -259,18 +261,6 @@ public class TransactionInput extends ChildMessage {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human readable debug string.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return isCoinBase() ? "TxIn: COINBASE" : "TxIn for [" + outpoint + "]: " + getScriptSig();
|
||||
} catch (ScriptException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ConnectionResult {
|
||||
NO_SUCH_TX,
|
||||
ALREADY_SPENT,
|
||||
@ -385,6 +375,14 @@ public class TransactionInput extends ChildMessage {
|
||||
return sequence != NO_SEQUENCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this input will cause a transaction to opt into the
|
||||
* <a href="https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki">full replace-by-fee </a> semantics.
|
||||
*/
|
||||
public boolean isOptInFullRBF() {
|
||||
return sequence < NO_SEQUENCE - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a connected transaction, runs the script against the connected pubkey and verifies they are correct.
|
||||
* @throws ScriptException if the script did not verify.
|
||||
@ -467,4 +465,26 @@ public class TransactionInput extends ChildMessage {
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(sequence, outpoint, Arrays.hashCode(scriptBytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human readable debug string.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder("TxIn");
|
||||
try {
|
||||
if (isCoinBase()) {
|
||||
s.append(": COINBASE");
|
||||
} else {
|
||||
s.append(" for [").append(outpoint).append("]: ").append(getScriptSig());
|
||||
String flags = Joiner.on(", ").skipNulls().join(hasSequence() ? "has sequence" : null,
|
||||
isOptInFullRBF() ? "opts into full RBF" : null);
|
||||
if (!flags.isEmpty())
|
||||
s.append(" (").append(flags).append(')');
|
||||
}
|
||||
return s.toString();
|
||||
} catch (ScriptException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -403,4 +403,14 @@ public class TransactionTest {
|
||||
final Transaction transaction = PARAMS.getDefaultSerializer().makeTransaction(transactionBytes);
|
||||
transaction.checkCoinBaseHeight(height);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optInFullRBF() {
|
||||
// a standard transaction as wallets would create
|
||||
Transaction tx = FakeTxBuilder.createFakeTx(PARAMS);
|
||||
assertFalse(tx.isOptInFullRBF());
|
||||
|
||||
tx.getInputs().get(0).setSequenceNumber(TransactionInput.NO_SEQUENCE - 2);
|
||||
assertTrue(tx.isOptInFullRBF());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user