transaction and script parsing improvements

This commit is contained in:
Craig Raw 2020-04-11 15:04:46 +02:00
parent 14767c3250
commit 0cebee3d22
6 changed files with 46 additions and 12 deletions

View file

@ -23,8 +23,14 @@ public class Script {
protected byte[] program;
public Script(byte[] programBytes) {
this(programBytes, true);
}
Script(byte[] programBytes, boolean parse) {
program = programBytes;
parse(programBytes);
if(parse) {
parse();
}
}
public Script(List<ScriptChunk> chunks) {
@ -38,7 +44,7 @@ public class Script {
new ScriptChunk(ScriptOpCodes.OP_CHECKSIG, null, 24),
};
private void parse(byte[] program) {
void parse() {
chunks = new ArrayList<>(5); // Common size.
ByteArrayInputStream bis = new ByteArrayInputStream(program);
int initialSize = bis.available();

View file

@ -110,12 +110,18 @@ public class ScriptChunk {
}
try {
new Script(data);
Script script = new Script(data);
//Flaky: Test if contains a non-zero opcode, otherwise not a script
for(ScriptChunk chunk : script.getChunks()) {
if(chunk.getOpcode() != OP_0) {
return true;
}
}
} catch(ProtocolException e) {
return false;
}
return true;
return false;
}
public Script getScript() {

View file

@ -291,25 +291,25 @@ public class ScriptOpCodes {
}
/**
* Converts the given OpCode into a string (eg "0", "PUSHDATA", or "NON_OP(10)")
* Converts the given OpCode into a string (eg "0", "PUSHDATA", or "RETURN_10")
*/
public static String getOpCodeName(int opcode) {
if (opCodeNameMap.containsKey((Integer)opcode)) {
return opCodeNameMap.get(opcode);
}
return "NON_OP(" + opcode + ")";
return "RETURN_" + opcode;
}
/**
* Converts the given pushdata OpCode into a string (eg "PUSHDATA2", or "PUSHDATA(23)")
* Converts the given pushdata OpCode into a string (eg "PUSHDATA_2", or "PUSHDATA_23")
*/
public static String getPushDataName(int opcode) {
if (opCodeNameMap.containsKey(opcode)) {
return opCodeNameMap.get(opcode);
}
return "PUSHDATA(" + opcode + ")";
return "PUSHDATA_" + opcode;
}
/**

View file

@ -320,6 +320,12 @@ public class Transaction extends TransactionPart {
return inputs.size() == 1 && inputs.get(0).isCoinBase();
}
public static boolean isTransaction(byte[] bytes) {
//Incomplete quick test
long version = Utils.readUint32(bytes, 0);
return version > 0 && version < 5;
}
public Sha256Hash hashForSignature(int inputIndex, Script redeemScript, SigHash type, boolean anyoneCanPay) {
int sigHash = TransactionSignature.calcSigHashValue(type, anyoneCanPay);
return hashForSignature(inputIndex, redeemScript.getProgram(), (byte) sigHash);

View file

@ -45,7 +45,17 @@ public class TransactionInput extends TransactionPart {
public Script getScriptSig() {
if(scriptSig == null) {
scriptSig = new Script(scriptBytes);
if(isCoinBase()) {
//ScriptSig may be invalid, attempt to parse
scriptSig = new Script(scriptBytes, false);
try {
scriptSig.parse();
} catch (ProtocolException e) {
scriptSig = new Script(scriptSig.getChunks());
}
} else {
scriptSig = new Script(scriptBytes);
}
}
return scriptSig;

View file

@ -519,9 +519,15 @@ public class PSBT {
}
public static boolean isPSBT(byte[] b) {
ByteBuffer buffer = ByteBuffer.wrap(b);
int header = buffer.getInt();
return header == PSBT_MAGIC_INT;
try {
ByteBuffer buffer = ByteBuffer.wrap(b);
int header = buffer.getInt();
return header == PSBT_MAGIC_INT;
} catch (Exception e) {
//ignore
}
return false;
}
public static boolean isPSBT(String s) {