3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-12 10:15:52 +00:00

Eliminate the duplicated parentTransaction field from TransactionInput/Output.

This commit is contained in:
Mike Hearn 2014-08-12 15:44:59 +02:00
parent 20447bc340
commit a30cdfed0c
3 changed files with 32 additions and 39 deletions

View File

@ -20,13 +20,11 @@ import javax.annotation.Nullable;
/** /**
* Represents a Message type that can be contained within another Message. ChildMessages that have a cached * Represents a Message type that can be contained within another Message. ChildMessages that have a cached
* backing byte array need to invalidate their parent's caches as well as their own if they are modified. * backing byte array need to invalidate their parent's caches as well as their own if they are modified.
*
* @author git
*/ */
public abstract class ChildMessage extends Message { public abstract class ChildMessage extends Message {
private static final long serialVersionUID = -7657113383624517931L; private static final long serialVersionUID = -7657113383624517931L;
@Nullable private Message parent; @Nullable protected Message parent;
protected ChildMessage() { protected ChildMessage() {
} }

View File

@ -58,13 +58,11 @@ public class TransactionInput extends ChildMessage implements Serializable {
/** Value of the output connected to the input, if known. This field does not participate in equals()/hashCode(). */ /** Value of the output connected to the input, if known. This field does not participate in equals()/hashCode(). */
@Nullable @Nullable
private final Coin value; private final Coin value;
// A pointer to the transaction that owns this input.
private final Transaction parentTransaction;
/** /**
* Creates an input that connects to nothing - used only in creation of coinbase transactions. * Creates an input that connects to nothing - used only in creation of coinbase transactions.
*/ */
public TransactionInput(NetworkParameters params, Transaction parentTransaction, byte[] scriptBytes) { public TransactionInput(NetworkParameters params, @Nullable Transaction parentTransaction, byte[] scriptBytes) {
this(params, parentTransaction, scriptBytes, new TransactionOutPoint(params, NO_SEQUENCE, (Transaction) null)); this(params, parentTransaction, scriptBytes, new TransactionOutPoint(params, NO_SEQUENCE, (Transaction) null));
} }
@ -79,8 +77,8 @@ public class TransactionInput extends ChildMessage implements Serializable {
this.scriptBytes = scriptBytes; this.scriptBytes = scriptBytes;
this.outpoint = outpoint; this.outpoint = outpoint;
this.sequence = NO_SEQUENCE; this.sequence = NO_SEQUENCE;
this.parentTransaction = parentTransaction;
this.value = value; this.value = value;
setParent(parentTransaction);
length = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length); length = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length);
} }
@ -90,10 +88,10 @@ public class TransactionInput extends ChildMessage implements Serializable {
TransactionInput(NetworkParameters params, Transaction parentTransaction, TransactionOutput output) { TransactionInput(NetworkParameters params, Transaction parentTransaction, TransactionOutput output) {
super(params); super(params);
long outputIndex = output.getIndex(); long outputIndex = output.getIndex();
outpoint = new TransactionOutPoint(params, outputIndex, output.parentTransaction); outpoint = new TransactionOutPoint(params, outputIndex, output.getParentTransaction());
scriptBytes = EMPTY_ARRAY; scriptBytes = EMPTY_ARRAY;
sequence = NO_SEQUENCE; sequence = NO_SEQUENCE;
this.parentTransaction = parentTransaction; setParent(parentTransaction);
this.value = output.getValue(); this.value = output.getValue();
length = 41; length = 41;
} }
@ -104,7 +102,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
public TransactionInput(NetworkParameters params, Transaction parentTransaction, public TransactionInput(NetworkParameters params, Transaction parentTransaction,
byte[] payload, int offset) throws ProtocolException { byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset); super(params, payload, offset);
this.parentTransaction = parentTransaction; setParent(checkNotNull(parentTransaction));
this.value = null; this.value = null;
} }
@ -124,7 +122,6 @@ public class TransactionInput extends ChildMessage implements Serializable {
boolean parseLazy, boolean parseRetain) boolean parseLazy, boolean parseRetain)
throws ProtocolException { throws ProtocolException {
super(params, payload, offset, parentTransaction, parseLazy, parseRetain, UNKNOWN_LENGTH); super(params, payload, offset, parentTransaction, parseLazy, parseRetain, UNKNOWN_LENGTH);
this.parentTransaction = parentTransaction;
this.value = null; this.value = null;
} }
@ -261,7 +258,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
* @return The Transaction that owns this input. * @return The Transaction that owns this input.
*/ */
public Transaction getParentTransaction() { public Transaction getParentTransaction() {
return parentTransaction; return (Transaction) parent;
} }
/** /**
@ -344,13 +341,13 @@ public class TransactionInput extends ChildMessage implements Serializable {
checkElementIndex((int) outpoint.getIndex(), transaction.getOutputs().size(), "Corrupt transaction"); checkElementIndex((int) outpoint.getIndex(), transaction.getOutputs().size(), "Corrupt transaction");
TransactionOutput out = transaction.getOutput((int) outpoint.getIndex()); TransactionOutput out = transaction.getOutput((int) outpoint.getIndex());
if (!out.isAvailableForSpending()) { if (!out.isAvailableForSpending()) {
if (out.parentTransaction.equals(outpoint.fromTx)) { if (getParentTransaction().equals(outpoint.fromTx)) {
// Already connected. // Already connected.
return ConnectionResult.SUCCESS; return ConnectionResult.SUCCESS;
} else if (mode == ConnectMode.DISCONNECT_ON_CONFLICT) { } else if (mode == ConnectMode.DISCONNECT_ON_CONFLICT) {
out.markAsUnspent(); out.markAsUnspent();
} else if (mode == ConnectMode.ABORT_ON_CONFLICT) { } else if (mode == ConnectMode.ABORT_ON_CONFLICT) {
outpoint.fromTx = checkNotNull(out.parentTransaction); outpoint.fromTx = out.getParentTransaction();
return TransactionInput.ConnectionResult.ALREADY_SPENT; return TransactionInput.ConnectionResult.ALREADY_SPENT;
} }
} }
@ -360,7 +357,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
/** Internal use only: connects this TransactionInput to the given output (updates pointers and spent flags) */ /** Internal use only: connects this TransactionInput to the given output (updates pointers and spent flags) */
public void connect(TransactionOutput out) { public void connect(TransactionOutput out) {
outpoint.fromTx = checkNotNull(out.parentTransaction); outpoint.fromTx = out.getParentTransaction();
out.markAsSpent(this); out.markAsSpent(this);
} }
@ -421,15 +418,15 @@ public class TransactionInput extends ChildMessage implements Serializable {
* @throws VerificationException If the outpoint doesn't match the given output. * @throws VerificationException If the outpoint doesn't match the given output.
*/ */
public void verify(TransactionOutput output) throws VerificationException { public void verify(TransactionOutput output) throws VerificationException {
if (output.parentTransaction != null) { if (output.parent != null) {
if (!getOutpoint().getHash().equals(output.parentTransaction.getHash())) if (!getOutpoint().getHash().equals(output.getParentTransaction().getHash()))
throw new VerificationException("This input does not refer to the tx containing the output."); throw new VerificationException("This input does not refer to the tx containing the output.");
if (getOutpoint().getIndex() != output.getIndex()) if (getOutpoint().getIndex() != output.getIndex())
throw new VerificationException("This input refers to a different output on the given tx."); throw new VerificationException("This input refers to a different output on the given tx.");
} }
Script pubKey = output.getScriptPubKey(); Script pubKey = output.getScriptPubKey();
int myIndex = parentTransaction.getInputs().indexOf(this); int myIndex = getParentTransaction().getInputs().indexOf(this);
getScriptSig().correctlySpends(parentTransaction, myIndex, pubKey, true); getScriptSig().correctlySpends(getParentTransaction(), myIndex, pubKey, true);
} }
/** /**
@ -458,7 +455,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
if (!outpoint.equals(input.outpoint)) return false; if (!outpoint.equals(input.outpoint)) return false;
if (!Arrays.equals(scriptBytes, input.scriptBytes)) return false; if (!Arrays.equals(scriptBytes, input.scriptBytes)) return false;
if (scriptSig != null ? !scriptSig.equals(input.scriptSig) : input.scriptSig != null) return false; if (scriptSig != null ? !scriptSig.equals(input.scriptSig) : input.scriptSig != null) return false;
if (parentTransaction != input.parentTransaction) return false; if (parent != input.parent) return false;
return true; return true;
} }

View File

@ -59,8 +59,6 @@ public class TransactionOutput extends ChildMessage implements Serializable {
private boolean availableForSpending; private boolean availableForSpending;
@Nullable private TransactionInput spentBy; @Nullable private TransactionInput spentBy;
// A reference to the transaction which holds this output, if any.
@Nullable Transaction parentTransaction;
private transient int scriptLen; private transient int scriptLen;
/** /**
@ -69,7 +67,7 @@ public class TransactionOutput extends ChildMessage implements Serializable {
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, byte[] payload, public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, byte[] payload,
int offset) throws ProtocolException { int offset) throws ProtocolException {
super(params, payload, offset); super(params, payload, offset);
parentTransaction = parent; setParent(parent);
availableForSpending = true; availableForSpending = true;
} }
@ -88,7 +86,6 @@ public class TransactionOutput extends ChildMessage implements Serializable {
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, byte[] payload, int offset, public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, byte[] payload, int offset,
boolean parseLazy, boolean parseRetain) throws ProtocolException { boolean parseLazy, boolean parseRetain) throws ProtocolException {
super(params, payload, offset, parent, parseLazy, parseRetain, UNKNOWN_LENGTH); super(params, payload, offset, parent, parseLazy, parseRetain, UNKNOWN_LENGTH);
parentTransaction = parent;
availableForSpending = true; availableForSpending = true;
} }
@ -118,7 +115,7 @@ public class TransactionOutput extends ChildMessage implements Serializable {
checkArgument(value.compareTo(NetworkParameters.MAX_MONEY) < 0, "Values larger than MAX_MONEY not allowed"); checkArgument(value.compareTo(NetworkParameters.MAX_MONEY) < 0, "Values larger than MAX_MONEY not allowed");
this.value = value.value; this.value = value.value;
this.scriptBytes = scriptBytes; this.scriptBytes = scriptBytes;
parentTransaction = parent; setParent(parent);
availableForSpending = true; availableForSpending = true;
length = 8 + VarInt.sizeOf(scriptBytes.length) + scriptBytes.length; length = 8 + VarInt.sizeOf(scriptBytes.length) + scriptBytes.length;
} }
@ -218,14 +215,16 @@ public class TransactionOutput extends ChildMessage implements Serializable {
this.value = value.value; this.value = value.value;
} }
int getIndex() { /**
checkNotNull(parentTransaction, "This output is not attached to a parent transaction."); * Gets the index of this output in the parent transaction, or throws if this output is free standing. Iterates
for (int i = 0; i < parentTransaction.getOutputs().size(); i++) { * over the parents list to discover this.
if (parentTransaction.getOutputs().get(i) == this) */
public int getIndex() {
for (int i = 0; i < getParentTransaction().getOutputs().size(); i++) {
if (getParentTransaction().getOutputs().get(i) == this)
return i; return i;
} }
// Should never happen. throw new IllegalStateException("Output linked to wrong parent transaction?");
throw new RuntimeException("Output linked to wrong parent transaction?");
} }
/** /**
@ -270,8 +269,8 @@ public class TransactionOutput extends ChildMessage implements Serializable {
checkState(availableForSpending); checkState(availableForSpending);
availableForSpending = false; availableForSpending = false;
spentBy = input; spentBy = input;
if (parentTransaction != null) if (parent != null)
log.info("Marked {}:{} as spent by {}", parentTransaction.getHash(), getIndex(), input); log.info("Marked {}:{} as spent by {}", getParentTransaction().getHash(), getIndex(), input);
else else
log.info("Marked floating output as spent by {}", input); log.info("Marked floating output as spent by {}", input);
} }
@ -280,8 +279,8 @@ public class TransactionOutput extends ChildMessage implements Serializable {
* Resets the spent pointer / availableForSpending flag to null. * Resets the spent pointer / availableForSpending flag to null.
*/ */
public void markAsUnspent() { public void markAsUnspent() {
if (parentTransaction != null) if (parent != null)
log.info("Un-marked {}:{} as spent by {}", parentTransaction.getHash(), getIndex(), spentBy); log.info("Un-marked {}:{} as spent by {}", getParentTransaction().getHash(), getIndex(), spentBy);
else else
log.info("Un-marked floating output as spent by {}", spentBy); log.info("Un-marked floating output as spent by {}", spentBy);
availableForSpending = true; availableForSpending = true;
@ -388,7 +387,7 @@ public class TransactionOutput extends ChildMessage implements Serializable {
* Returns the transaction that owns this output, or throws NullPointerException if unowned. * Returns the transaction that owns this output, or throws NullPointerException if unowned.
*/ */
public Transaction getParentTransaction() { public Transaction getParentTransaction() {
return checkNotNull(parentTransaction, "Free-standing TransactionOutput"); return checkNotNull((Transaction) parent, "Free-standing TransactionOutput");
} }
/** /**
@ -423,14 +422,13 @@ public class TransactionOutput extends ChildMessage implements Serializable {
if (!Arrays.equals(scriptBytes, other.scriptBytes)) return false; if (!Arrays.equals(scriptBytes, other.scriptBytes)) return false;
if (value != other.value) return false; if (value != other.value) return false;
if (parentTransaction != null && parentTransaction != other.parentTransaction) return false; if (parent != null && parent != other.parent) return false;
return true; return true;
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = 31 * (int) value + (scriptBytes != null ? Arrays.hashCode(scriptBytes) : 0); return 31 * (int) value + (scriptBytes != null ? Arrays.hashCode(scriptBytes) : 0);
return result;
} }
} }