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
* 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 {
private static final long serialVersionUID = -7657113383624517931L;
@Nullable private Message parent;
@Nullable protected Message parent;
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(). */
@Nullable
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.
*/
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));
}
@ -79,8 +77,8 @@ public class TransactionInput extends ChildMessage implements Serializable {
this.scriptBytes = scriptBytes;
this.outpoint = outpoint;
this.sequence = NO_SEQUENCE;
this.parentTransaction = parentTransaction;
this.value = value;
setParent(parentTransaction);
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) {
super(params);
long outputIndex = output.getIndex();
outpoint = new TransactionOutPoint(params, outputIndex, output.parentTransaction);
outpoint = new TransactionOutPoint(params, outputIndex, output.getParentTransaction());
scriptBytes = EMPTY_ARRAY;
sequence = NO_SEQUENCE;
this.parentTransaction = parentTransaction;
setParent(parentTransaction);
this.value = output.getValue();
length = 41;
}
@ -104,7 +102,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
public TransactionInput(NetworkParameters params, Transaction parentTransaction,
byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset);
this.parentTransaction = parentTransaction;
setParent(checkNotNull(parentTransaction));
this.value = null;
}
@ -124,7 +122,6 @@ public class TransactionInput extends ChildMessage implements Serializable {
boolean parseLazy, boolean parseRetain)
throws ProtocolException {
super(params, payload, offset, parentTransaction, parseLazy, parseRetain, UNKNOWN_LENGTH);
this.parentTransaction = parentTransaction;
this.value = null;
}
@ -261,7 +258,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
* @return The Transaction that owns this input.
*/
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");
TransactionOutput out = transaction.getOutput((int) outpoint.getIndex());
if (!out.isAvailableForSpending()) {
if (out.parentTransaction.equals(outpoint.fromTx)) {
if (getParentTransaction().equals(outpoint.fromTx)) {
// Already connected.
return ConnectionResult.SUCCESS;
} else if (mode == ConnectMode.DISCONNECT_ON_CONFLICT) {
out.markAsUnspent();
} else if (mode == ConnectMode.ABORT_ON_CONFLICT) {
outpoint.fromTx = checkNotNull(out.parentTransaction);
outpoint.fromTx = out.getParentTransaction();
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) */
public void connect(TransactionOutput out) {
outpoint.fromTx = checkNotNull(out.parentTransaction);
outpoint.fromTx = out.getParentTransaction();
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.
*/
public void verify(TransactionOutput output) throws VerificationException {
if (output.parentTransaction != null) {
if (!getOutpoint().getHash().equals(output.parentTransaction.getHash()))
if (output.parent != null) {
if (!getOutpoint().getHash().equals(output.getParentTransaction().getHash()))
throw new VerificationException("This input does not refer to the tx containing the output.");
if (getOutpoint().getIndex() != output.getIndex())
throw new VerificationException("This input refers to a different output on the given tx.");
}
Script pubKey = output.getScriptPubKey();
int myIndex = parentTransaction.getInputs().indexOf(this);
getScriptSig().correctlySpends(parentTransaction, myIndex, pubKey, true);
int myIndex = getParentTransaction().getInputs().indexOf(this);
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 (!Arrays.equals(scriptBytes, input.scriptBytes)) 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;
}

View File

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