transaction headers retrieval and edit

This commit is contained in:
Craig Raw 2020-03-28 10:44:50 +02:00
parent 566aa2e953
commit 7fb5601de3
3 changed files with 82 additions and 7 deletions

View file

@ -24,6 +24,8 @@ public class Transaction extends TransactionPart {
private long version; private long version;
private long lockTime; private long lockTime;
private boolean segwit;
private int segwitVersion;
private Sha256Hash cachedTxId; private Sha256Hash cachedTxId;
private Sha256Hash cachedWTxId; private Sha256Hash cachedWTxId;
@ -39,10 +41,18 @@ public class Transaction extends TransactionPart {
return version; return version;
} }
public void setVersion(long version) {
this.version = version;
}
public long getLockTime() { public long getLockTime() {
return lockTime; return lockTime;
} }
public void setLockTime(long lockTime) {
this.lockTime = lockTime;
}
public Sha256Hash getTxId() { public Sha256Hash getTxId() {
if (cachedTxId == null) { if (cachedTxId == null) {
if (!hasWitnesses() && cachedWTxId != null) { if (!hasWitnesses() && cachedWTxId != null) {
@ -75,6 +85,18 @@ public class Transaction extends TransactionPart {
return Sha256Hash.wrapReversed(Sha256Hash.hashTwice(stream.toByteArray())); return Sha256Hash.wrapReversed(Sha256Hash.hashTwice(stream.toByteArray()));
} }
public boolean isSegwit() {
return segwit;
}
public int getSegwitVersion() {
return segwitVersion;
}
public void setSegwitVersion(int segwitVersion) {
this.segwitVersion = segwitVersion;
}
public boolean hasWitnesses() { public boolean hasWitnesses() {
for (TransactionInput in : inputs) for (TransactionInput in : inputs)
if (in.hasWitness()) if (in.hasWitness())
@ -83,7 +105,7 @@ public class Transaction extends TransactionPart {
} }
public void bitcoinSerializeToStream(OutputStream stream) throws IOException { public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
boolean useSegwit = hasWitnesses(); boolean useSegwit = isSegwit();
bitcoinSerializeToStream(stream, useSegwit); bitcoinSerializeToStream(stream, useSegwit);
} }
@ -98,7 +120,7 @@ public class Transaction extends TransactionPart {
// marker, flag // marker, flag
if (useSegwit) { if (useSegwit) {
stream.write(0); stream.write(0);
stream.write(1); stream.write(segwitVersion);
} }
// txin_count, txins // txin_count, txins
stream.write(new VarInt(inputs.size()).encode()); stream.write(new VarInt(inputs.size()).encode());
@ -108,7 +130,7 @@ public class Transaction extends TransactionPart {
stream.write(new VarInt(outputs.size()).encode()); stream.write(new VarInt(outputs.size()).encode());
for (TransactionOutput out : outputs) for (TransactionOutput out : outputs)
out.bitcoinSerializeToStream(stream); out.bitcoinSerializeToStream(stream);
// script_witnisses // script_witnesses
if (useSegwit) { if (useSegwit) {
for (TransactionInput in : inputs) { for (TransactionInput in : inputs) {
in.getWitness().bitcoinSerializeToStream(stream); in.getWitness().bitcoinSerializeToStream(stream);
@ -128,17 +150,18 @@ public class Transaction extends TransactionPart {
version = readUint32(); version = readUint32();
// peek at marker // peek at marker
byte marker = rawtx[cursor]; byte marker = rawtx[cursor];
boolean useSegwit = marker == 0; segwit = (marker == 0);
// marker, flag // marker, flag
if (useSegwit) { if (segwit) {
readBytes(2); byte[] segwitHeader = readBytes(2);
segwitVersion = segwitHeader[1];
} }
// txin_count, txins // txin_count, txins
parseInputs(); parseInputs();
// txout_count, txouts // txout_count, txouts
parseOutputs(); parseOutputs();
// script_witnesses // script_witnesses
if (useSegwit) if (segwit)
parseWitnesses(); parseWitnesses();
// lock_time // lock_time
lockTime = readUint32(); lockTime = readUint32();
@ -182,6 +205,39 @@ public class Transaction extends TransactionPart {
} }
} }
public int getSize() {
return length;
}
public int getVirtualSize() {
int wu = 0;
// version
wu += 4*4;
// marker, flag
if(isSegwit()) {
wu += 2;
}
// txin_count, txins
wu += new VarInt(inputs.size()).getSizeInBytes() * 4;
for (TransactionInput in : inputs)
wu += in.length * 4;
// txout_count, txouts
wu += new VarInt(outputs.size()).getSizeInBytes() * 4;
for (TransactionOutput out : outputs)
wu += out.length * 4;
// script_witnesses
if(isSegwit()) {
for (TransactionInput in : inputs) {
wu += in.getWitness().getLength();
}
}
// lock_time
wu += 4*4;
return (int)Math.ceil((double)wu / 4.0);
}
public List<TransactionInput> getInputs() { public List<TransactionInput> getInputs() {
return Collections.unmodifiableList(inputs); return Collections.unmodifiableList(inputs);
} }

View file

@ -38,6 +38,14 @@ public abstract class TransactionPart {
this.parent = parent; this.parent = parent;
} }
public int getOffset() {
return offset;
}
public int getLength() {
return length;
}
/** /**
* This returns a correct value by parsing the message. * This returns a correct value by parsing the message.
*/ */

View file

@ -29,6 +29,17 @@ public class TransactionWitness {
return pushes.size(); return pushes.size();
} }
public int getLength() {
int length = new VarInt(pushes.size()).getSizeInBytes();
for (int i = 0; i < pushes.size(); i++) {
byte[] push = pushes.get(i);
length += new VarInt(push.length).getSizeInBytes();
length += push.length;
}
return length;
}
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException { protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(new VarInt(pushes.size()).encode()); stream.write(new VarInt(pushes.size()).encode());
for (int i = 0; i < pushes.size(); i++) { for (int i = 0; i < pushes.size(); i++) {