Skip to content

Commit

Permalink
Merge pull request #60 from twostack/expose-pre-image
Browse files Browse the repository at this point in the history
V2 Refactor
  • Loading branch information
stephanfeb authored Aug 14, 2023
2 parents 337c6c4 + 95423e0 commit bdd023f
Show file tree
Hide file tree
Showing 43 changed files with 3,206 additions and 2,778 deletions.
9 changes: 8 additions & 1 deletion lib/dartsv.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,15 @@ export 'src/script/svscript.dart';
export 'src/script/opcodes.dart';
export 'src/script/interpreter.dart';
export 'src/script/stack.dart';
export 'src/script/script_error.dart';
export 'src/script/script_chunk.dart';
export 'src/script/scriptflags.dart';
export 'src/transaction/transaction.dart';
export 'src/transaction/transaction_builder.dart';
export 'src/transaction/script_builder.dart';
export 'src/transaction/transaction_outpoint.dart';
export 'src/transaction/transaction_signer.dart';
export 'src/transaction/transaction_input.dart';
export 'src/transaction/transaction_output.dart';
export 'src/transaction/transaction_input.dart';
export 'src/encoding/base58check.dart';
Expand All @@ -31,7 +38,7 @@ export 'src/transaction/p2pk_builder.dart';
export 'src/transaction/p2pkh_builder.dart';
export 'src/transaction/p2ms_builder.dart';
export 'src/transaction/p2sh_builder.dart';
export 'src/transaction/data_builder.dart';
export 'src/transaction/unspendable_data_builder.dart';
export 'src/encoding/utils.dart';
export 'src/exceptions.dart';
export 'src/crypto/ecies.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/block/block.dart
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ class Block {
ByteDataWriter writer = ByteDataWriter();

//concatenate all transactions
List<int> txBuf = _transactions!.fold(<int>[], (List<int> prev, Transaction tx) => prev + HEX.decode(tx.serialize(performChecks: false)));
List<int> txBuf = _transactions!.fold(<int>[], (List<int> prev, Transaction tx) => prev + HEX.decode(tx.serialize()));

writer.write(_header!.buffer);
writer.write(varIntWriter(_transactions!.length).toList());
Expand Down
5 changes: 5 additions & 0 deletions lib/src/privatekey.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ class SVPrivateKey {
_svPublicKey = SVPublicKey.fromPrivateKey(this);
}


SVPrivateKey.fromBuffer(List<int> buffer, {NetworkType networkType = NetworkType.TEST}){
SVPrivateKey.fromHex(HEX.encode(buffer), networkType);
}

/// Construct a Private Key from the hexadecimal value representing the
/// BigInt value of (d) in ` Q = d * G `
///
Expand Down
4 changes: 4 additions & 0 deletions lib/src/publickey.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ class SVPublicKey {
// _publicKey = ECPublicKey(_point, _domainParams);
}

SVPublicKey.fromBuffer(List<int> buffer){
SVPublicKey.fromHex(HEX.encode(buffer));
}


/// Reconstruct a public key from the hexadecimal format of it's DER-encoding.
///
Expand Down
2 changes: 1 addition & 1 deletion lib/src/script/interpreter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ class Interpreter {
}

if (fExec && opcodenum >= 0 && opcodenum <= OpCodes.OP_PUSHDATA4) {
if (fRequireMinimal && !_script!.checkMinimalPush(_pc - 1)) {
if (fRequireMinimal && !chunk.checkMinimalPush(_pc - 1)) {
_errStr = 'SCRIPT_ERR_MINIMALDATA';
return false;
}
Expand Down
36 changes: 34 additions & 2 deletions lib/src/script/opcodes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ class OpCodes {
//thanks for the OpCode Map MoneyButton/bsv ;)
static const opcodeMap = {
// push value
'OP_FALSE': 0,
'OP_0': 0,
'OP_FALSE': 0,
'OP_PUSHDATA1': 76,
'OP_PUSHDATA2': 77,
'OP_PUSHDATA4': 78,
'OP_1NEGATE': 79,
'OP_RESERVED': 80,
'OP_TRUE': 81,
'OP_1': 81,
'OP_TRUE': 81,
'OP_2': 82,
'OP_3': 83,
'OP_4': 84,
Expand Down Expand Up @@ -294,9 +294,41 @@ class OpCodes {
static const int OP_PUBKEY = 254;
static const int OP_INVALIDOPCODE = 255;


// static final Map<int, String> opCodeNameMap = Map<int, String>()
// .addAll(opcodeMap.map((key, value) => MapEntry(value, key)))
// .put("FALSE", OP_FALSE)
// .put("TRUE", OP_TRUE)
// .put("NOP2", OP_NOP2)
// .build();

static String fromNum(int opcodenum) {
var codeList = opcodeMap.entries.where((element) => element.value == opcodenum);
return codeList.last.key;
}


/**
* Converts the given OpCode into a string (eg "0", "PUSHDATA", or "NON_OP(10)")
*/
static String getOpCodeName(int opcodenum){
// opcodeMap.map((key, value) => MapEntry(value, key)).;
if (opcodeMap.containsValue(opcodenum)) {
var entry = opcodeMap.entries.where((element) => element.value == opcodenum);
return entry.first.key;
}

return "NON_OP(${opcodenum})";
}

/**
* Converts the given OpCodeName into an int
*/
static int getOpCode(String opCodeName) {
if (opcodeMap.containsKey(opCodeName))
return opcodeMap[opCodeName]!;

return OP_INVALIDOPCODE;
}

}
172 changes: 172 additions & 0 deletions lib/src/script/script_chunk.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import 'dart:typed_data';

import 'package:dartsv/dartsv.dart';
import 'package:hex/hex.dart';

/// Utility class to represent a parsed 'token' in the encoded script.
class ScriptChunk {

List<int> _buf;
int _len;
int _opcodenum;

///Construct a ScriptChunk
///
/// [_buf] - Buffer containing data in case of OP_PUSHDATA
///
/// [_len] - length of _buf
///
/// [_opcodenum] - Bitcoin script OpCode. See [OpCodes].
///
ScriptChunk(this._buf, this._len, this._opcodenum);

/// Returns this script chunk's numeric opcode
///
int get opcodenum => _opcodenum;

/// Sets this script chunk's numeric opcode
///
set opcodenum(int value) {
_opcodenum = value;
}

/// Returns the length of the buffer in case of PUSHDATAx instruction. Zero otherwise.
///
int get len => _len;

/// Sets the length of data contained in PUSHDATAx instruction. Zero otherwise.
///
set len(int value) {
_len = value;
}

/// Returns the byte array containing the data from a PUSHDATAx instruction.
///
List<int> get buf => _buf;

/// Sets the byte array of representing PUSHDATAx instruction.
///
set buf(List<int> value) {
_buf = value;
}

bool equalsOpCode(int opcode) {
return opcode == _opcodenum;
}

/**
* If this chunk is a single byte of non-pushdata content (could be OP_RESERVED or some invalid Opcode)
*/
bool isOpCode() {
return _opcodenum > OpCodes.OP_PUSHDATA4;
}

/**
* Returns true if this chunk is pushdata content, including the single-byte pushdatas.
*/
bool isPushData() {
return _opcodenum <= OpCodes.OP_16;
}

/** If this chunk is an OP_N opcode returns the equivalent integer value. */
int decodeOpN() {
return SVScript.decodeFromOpN(_opcodenum);
}

int size() {
final int opcodeLength = 1;

int pushDataSizeLength = 0;
if (_opcodenum == OpCodes.OP_PUSHDATA1) pushDataSizeLength = 1;
else if (_opcodenum == OpCodes.OP_PUSHDATA2) pushDataSizeLength = 2;
else if (_opcodenum == OpCodes.OP_PUSHDATA4) pushDataSizeLength = 4;

final int dataLength = _buf == null ? 0 : _buf.length;

return opcodeLength + pushDataSizeLength + dataLength;
}


/// Checks to see if the PUSHDATA instruction is using the *smallest* pushdata opcode it can.
///
/// [i] - Index of ScriptChunk. This should be a pushdata instruction.
///
/// Returns true if the *smallest* pushdata opcode was used.
bool checkMinimalPush(int i) {

if (_buf.isEmpty) {
// Could have used OP_0.
return (_opcodenum == OpCodes.OP_0);
} else if (_buf.length == 1 && buf[0] >= 1 && buf[0] <= 16) {
// Could have used OP_1 .. OP_16.
return _opcodenum == OpCodes.OP_1 + (buf[0] - 1);
} else if (_buf.length == 1 && buf[0] == 0x81) {
// Could have used OP_1NEGATE
return _opcodenum == OpCodes.OP_1NEGATE;
} else if (_buf.length <= 75) {
// Could have used a direct push (opcode indicating number of bytes pushed + those bytes).
return _opcodenum == buf.length;
} else if (_buf.length <= 255) {
// Could have used OP_PUSHDATA.
return _opcodenum == OpCodes.OP_PUSHDATA1;
} else if (_buf.length <= 65535) {
// Could have used OP_PUSHDATA2.
return _opcodenum == OpCodes.OP_PUSHDATA2;
}
return true;
}

String toEncodedString(bool asm){
StringBuffer str = new StringBuffer();
if (_buf == null || _buf.length <= 0) {

// no data chunk
if (!OpCodes.getOpCodeName(opcodenum).startsWith("NON_OP")) {
if (asm) {
// A few cases where the opcode name differs from reverseMap
// aside from 1 to 16 data pushes.
if (opcodenum == 0) {
// OP_0 -> 0
str.write("0");
} else if (opcodenum == 79) {
// OP_1NEGATE -> 1
str.write("-1");
} else {
str.write( OpCodes.getOpCodeName(opcodenum));
}
} else {
str.write( OpCodes.getOpCodeName(opcodenum));
}
} else {
String numstr = HEX.encode([opcodenum]);

//uneven numbers get padded with a leading zero
if (numstr.length % 2 != 0) {
numstr = "0" + numstr;
}
if (asm) {
str.write( numstr);
} else {
str.write("0x" + numstr);
}
}
} else {
// data chunk
if (!asm && (opcodenum == OpCodes.OP_PUSHDATA1 ||
opcodenum == OpCodes.OP_PUSHDATA2 ||
opcodenum == OpCodes.OP_PUSHDATA4)) {
str.write( OpCodes.getOpCodeName(opcodenum) + " ");
}
if (_buf.length > 0) {
if (asm) {
str.write(HEX.encode(_buf));
} else {
str.write("${_buf.length} 0x${HEX.encode(_buf)}");
}
}
}
return str.toString();
}


}
83 changes: 83 additions & 0 deletions lib/src/script/script_error.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@


import 'dart:core';
import 'dart:core';

enum ScriptError {

SCRIPT_ERR_OK("OK"),
SCRIPT_ERR_UNKNOWN_ERROR("UNKNOWN_ERROR"),
SCRIPT_ERR_EVAL_FALSE("EVAL_FALSE"),
SCRIPT_ERR_OP_RETURN("OP_RETURN"),
SCRIPT_ERR_SPLIT_RANGE("SPLIT_RANGE"),
SCRIPT_ERR_INVALID_NUMBER_RANGE("INVALID_NUMBER_RANGE"),
SCRIPT_ERR_NUMBER_OVERFLOW("SCRIPTNUM_OVERFLOW"),
SCRIPT_ERR_NUMBER_MINENCODE("SCRIPTNUM_MINENCODE"),
SCRIPT_ERR_DIV_BY_ZERO("DIV_BY_ZERO"),
SCRIPT_ERR_MOD_BY_ZERO("MOD_BY_ZERO"),
SCRIPT_ERR_NONCOMPRESSED_PUBKEY("NONCOMPRESSED_PUBKEY"),
SCRIPT_ERR_ILLEGAL_FORKID("ILLEGAL_FORKID"),
SCRIPT_ERR_SIGHASH_FORKID("SIGHASH_FORKID"),
SCRIPT_ERR_MUST_USE_FORKID("MUST_USE_FORKID"),

/* Max sizes */
SCRIPT_ERR_SCRIPT_SIZE("SCRIPT_SIZE"),
SCRIPT_ERR_PUSH_SIZE("PUSH_SIZE"),
SCRIPT_ERR_OP_COUNT("OP_COUNT"),
SCRIPT_ERR_STACK_SIZE("STACK_SIZE"),
SCRIPT_ERR_SIG_COUNT("SIG_COUNT"),
SCRIPT_ERR_PUBKEY_COUNT("PUBKEY_COUNT"),
SCRIPT_ERR_OPERAND_SIZE("OPERAND_SIZE"),

/* Failed verify operations */
SCRIPT_ERR_VERIFY("VERIFY"),
SCRIPT_ERR_EQUALVERIFY("EQUALVERIFY"),
SCRIPT_ERR_CHECKMULTISIGVERIFY("CHECKMULTISIGVERIFY"),
SCRIPT_ERR_CHECKSIGVERIFY("CHECKSIGVERIFY"),
SCRIPT_ERR_NUMEQUALVERIFY("NUMEQUALVERIFY"),

/* Logical/Format/Canonical errors */
SCRIPT_ERR_BAD_OPCODE("BAD_OPCODE"),
SCRIPT_ERR_DISABLED_OPCODE("DISABLED_OPCODE"),
SCRIPT_ERR_INVALID_STACK_OPERATION("INVALID_STACK_OPERATION"),
SCRIPT_ERR_INVALID_ALTSTACK_OPERATION("INVALID_ALTSTACK_OPERATION"),
SCRIPT_ERR_UNBALANCED_CONDITIONAL("UNBALANCED_CONDITIONAL"),

/* CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY */
SCRIPT_ERR_NEGATIVE_LOCKTIME("NEGATIVE_LOCKTIME"),
SCRIPT_ERR_UNSATISFIED_LOCKTIME("UNSATISFIED_LOCKTIME"),

/* Malleability */
SCRIPT_ERR_SIG_HASHTYPE("SIG_HASHTYPE"),
SCRIPT_ERR_SIG_DER("SIG_DER"),
SCRIPT_ERR_MINIMALDATA("MINIMALDATA"),
SCRIPT_ERR_SIG_PUSHONLY("SIG_PUSHONLY"),
SCRIPT_ERR_SIG_HIGH_S("SIG_HIGH_S"),
SCRIPT_ERR_SIG_NULLDUMMY("SIG_NULLDUMMY"),
SCRIPT_ERR_PUBKEYTYPE("PUBKEYTYPE"),
SCRIPT_ERR_CLEANSTACK("CLEANSTACK"),
SCRIPT_ERR_MINIMALIF("MINIMALIF"),
SCRIPT_ERR_SIG_NULLFAIL("NULLFAIL"),

/* softfork safeness */
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS("DISCOURAGE_UPGRADABLE_NOPS"),
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"),

/* segregated witness */
SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH("WITNESS_PROGRAM_WRONG_LENGTH"),
SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY("WITNESS_PROGRAM_WITNESS_EMPTY"),
SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH("WITNESS_PROGRAM_MISMATCH"),
SCRIPT_ERR_WITNESS_MALLEATED("WITNESS_MALLEATED"),
SCRIPT_ERR_WITNESS_MALLEATED_P2SH("WITNESS_MALLEATED_P2SH"),
SCRIPT_ERR_WITNESS_UNEXPECTED("WITNESS_UNEXPECTED"),
SCRIPT_ERR_WITNESS_PUBKEYTYPE("WITNESS_PUBKEYTYPE"),

SCRIPT_ERR_ERROR_COUNT("ERROR_COUNT");

final String _mnemonic;

const ScriptError(this._mnemonic);

String get mnemonic => _mnemonic;

}
Loading

0 comments on commit bdd023f

Please sign in to comment.