
com.bccapi.bitlib.model.Transaction Maven / Gradle / Ivy
package com.bccapi.bitlib.model;
import com.bccapi.bitlib.model.TransactionInput.TransactionInputParsingException;
import com.bccapi.bitlib.model.TransactionOutput.TransactionOutputParsingException;
import com.bccapi.bitlib.util.ByteReader;
import com.bccapi.bitlib.util.ByteReader.InsufficientBytesException;
import com.bccapi.bitlib.util.ByteWriter;
import com.bccapi.bitlib.util.HashUtils;
import com.bccapi.bitlib.util.Sha256Hash;
public class Transaction {
public static class TransactionParsingException extends Exception {
private static final long serialVersionUID = 1L;
public TransactionParsingException(String message) {
super(message);
}
public TransactionParsingException(String message, Exception e) {
super(message, e);
}
}
public static final int MIN_TRANSACTION_SIZE = 100;
public int version;
public TransactionInput[] inputs;
public TransactionOutput[] outputs;
public int lockTime;
private Sha256Hash _hash;
public static Transaction fromByteReader(ByteReader reader) throws TransactionParsingException {
try {
int version = reader.getIntLE();
int numInputs = (int) reader.getCompactInt();
TransactionInput[] inputs = new TransactionInput[numInputs];
for (int i = 0; i < numInputs; i++) {
try {
inputs[i] = TransactionInput.fromByteReader(reader);
} catch (TransactionInputParsingException e) {
throw new TransactionParsingException("Unable to parse tranaction input at index " + i + ": "
+ e.getMessage());
}
}
int numOutputs = (int) reader.getCompactInt();
TransactionOutput[] outputs = new TransactionOutput[numOutputs];
for (int i = 0; i < numOutputs; i++) {
try {
outputs[i] = TransactionOutput.fromByteReader(reader);
} catch (TransactionOutputParsingException e) {
throw new TransactionParsingException("Unable to parse tranaction output at index " + i + ": "
+ e.getMessage());
}
}
int lockTime = reader.getIntLE();
Transaction t = new Transaction(version, inputs, outputs, lockTime);
return t;
} catch (InsufficientBytesException e) {
throw new TransactionParsingException(e.getMessage());
}
}
public Transaction copy() {
try {
return Transaction.fromByteReader(new ByteReader(toBytes()));
} catch (TransactionParsingException e) {
// This should never happen
throw new RuntimeException(e);
}
}
public byte[] toBytes() {
ByteWriter writer = new ByteWriter(1024);
toByteWriter(writer);
return writer.toBytes();
}
public void toByteWriter(ByteWriter writer) {
writer.putIntLE(version);
writer.putCompactInt(inputs.length);
for (TransactionInput input : inputs) {
input.toByteWriter(writer);
}
writer.putCompactInt(outputs.length);
for (TransactionOutput output : outputs) {
output.toByteWriter(writer);
}
writer.putIntLE(lockTime);
}
public Transaction(int version, TransactionInput[] inputs, TransactionOutput[] outputs, int lockTime) {
this.version = version;
this.inputs = inputs;
this.outputs = outputs;
this.lockTime = lockTime;
}
public Sha256Hash getHash() {
if (_hash == null) {
ByteWriter writer = new ByteWriter(2000);
toByteWriter(writer);
_hash = new Sha256Hash(HashUtils.doubleSha256(writer.toBytes()), true);
}
return _hash;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getHash()).append(" in: ").append(inputs.length).append(" out: ").append(outputs.length);
return sb.toString();
}
@Override
public int hashCode() {
return getHash().hashCode();
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof Transaction)) {
return false;
}
return getHash().equals(((Transaction) other).getHash());
}
public boolean isCoinbase() {
for (TransactionInput in : inputs) {
if (in.script instanceof ScriptInputCoinbase) {
return true;
}
}
return false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy