|
@ -25,6 +25,7 @@ |
|
|
|
|
|
|
|
|
import hashlib |
|
|
import hashlib |
|
|
from typing import List, Tuple, TYPE_CHECKING, Optional, Union |
|
|
from typing import List, Tuple, TYPE_CHECKING, Optional, Union |
|
|
|
|
|
from enum import IntEnum |
|
|
|
|
|
|
|
|
from .util import bfh, bh2u, BitcoinException, assert_bytes, to_bytes, inv_dict |
|
|
from .util import bfh, bh2u, BitcoinException, assert_bytes, to_bytes, inv_dict |
|
|
from . import version |
|
|
from . import version |
|
@ -49,6 +50,147 @@ TYPE_PUBKEY = 1 |
|
|
TYPE_SCRIPT = 2 |
|
|
TYPE_SCRIPT = 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class opcodes(IntEnum): |
|
|
|
|
|
# push value |
|
|
|
|
|
OP_0 = 0x00 |
|
|
|
|
|
OP_FALSE = OP_0 |
|
|
|
|
|
OP_PUSHDATA1 = 0x4c |
|
|
|
|
|
OP_PUSHDATA2 = 0x4d |
|
|
|
|
|
OP_PUSHDATA4 = 0x4e |
|
|
|
|
|
OP_1NEGATE = 0x4f |
|
|
|
|
|
OP_RESERVED = 0x50 |
|
|
|
|
|
OP_1 = 0x51 |
|
|
|
|
|
OP_TRUE = OP_1 |
|
|
|
|
|
OP_2 = 0x52 |
|
|
|
|
|
OP_3 = 0x53 |
|
|
|
|
|
OP_4 = 0x54 |
|
|
|
|
|
OP_5 = 0x55 |
|
|
|
|
|
OP_6 = 0x56 |
|
|
|
|
|
OP_7 = 0x57 |
|
|
|
|
|
OP_8 = 0x58 |
|
|
|
|
|
OP_9 = 0x59 |
|
|
|
|
|
OP_10 = 0x5a |
|
|
|
|
|
OP_11 = 0x5b |
|
|
|
|
|
OP_12 = 0x5c |
|
|
|
|
|
OP_13 = 0x5d |
|
|
|
|
|
OP_14 = 0x5e |
|
|
|
|
|
OP_15 = 0x5f |
|
|
|
|
|
OP_16 = 0x60 |
|
|
|
|
|
|
|
|
|
|
|
# control |
|
|
|
|
|
OP_NOP = 0x61 |
|
|
|
|
|
OP_VER = 0x62 |
|
|
|
|
|
OP_IF = 0x63 |
|
|
|
|
|
OP_NOTIF = 0x64 |
|
|
|
|
|
OP_VERIF = 0x65 |
|
|
|
|
|
OP_VERNOTIF = 0x66 |
|
|
|
|
|
OP_ELSE = 0x67 |
|
|
|
|
|
OP_ENDIF = 0x68 |
|
|
|
|
|
OP_VERIFY = 0x69 |
|
|
|
|
|
OP_RETURN = 0x6a |
|
|
|
|
|
|
|
|
|
|
|
# stack ops |
|
|
|
|
|
OP_TOALTSTACK = 0x6b |
|
|
|
|
|
OP_FROMALTSTACK = 0x6c |
|
|
|
|
|
OP_2DROP = 0x6d |
|
|
|
|
|
OP_2DUP = 0x6e |
|
|
|
|
|
OP_3DUP = 0x6f |
|
|
|
|
|
OP_2OVER = 0x70 |
|
|
|
|
|
OP_2ROT = 0x71 |
|
|
|
|
|
OP_2SWAP = 0x72 |
|
|
|
|
|
OP_IFDUP = 0x73 |
|
|
|
|
|
OP_DEPTH = 0x74 |
|
|
|
|
|
OP_DROP = 0x75 |
|
|
|
|
|
OP_DUP = 0x76 |
|
|
|
|
|
OP_NIP = 0x77 |
|
|
|
|
|
OP_OVER = 0x78 |
|
|
|
|
|
OP_PICK = 0x79 |
|
|
|
|
|
OP_ROLL = 0x7a |
|
|
|
|
|
OP_ROT = 0x7b |
|
|
|
|
|
OP_SWAP = 0x7c |
|
|
|
|
|
OP_TUCK = 0x7d |
|
|
|
|
|
|
|
|
|
|
|
# splice ops |
|
|
|
|
|
OP_CAT = 0x7e |
|
|
|
|
|
OP_SUBSTR = 0x7f |
|
|
|
|
|
OP_LEFT = 0x80 |
|
|
|
|
|
OP_RIGHT = 0x81 |
|
|
|
|
|
OP_SIZE = 0x82 |
|
|
|
|
|
|
|
|
|
|
|
# bit logic |
|
|
|
|
|
OP_INVERT = 0x83 |
|
|
|
|
|
OP_AND = 0x84 |
|
|
|
|
|
OP_OR = 0x85 |
|
|
|
|
|
OP_XOR = 0x86 |
|
|
|
|
|
OP_EQUAL = 0x87 |
|
|
|
|
|
OP_EQUALVERIFY = 0x88 |
|
|
|
|
|
OP_RESERVED1 = 0x89 |
|
|
|
|
|
OP_RESERVED2 = 0x8a |
|
|
|
|
|
|
|
|
|
|
|
# numeric |
|
|
|
|
|
OP_1ADD = 0x8b |
|
|
|
|
|
OP_1SUB = 0x8c |
|
|
|
|
|
OP_2MUL = 0x8d |
|
|
|
|
|
OP_2DIV = 0x8e |
|
|
|
|
|
OP_NEGATE = 0x8f |
|
|
|
|
|
OP_ABS = 0x90 |
|
|
|
|
|
OP_NOT = 0x91 |
|
|
|
|
|
OP_0NOTEQUAL = 0x92 |
|
|
|
|
|
|
|
|
|
|
|
OP_ADD = 0x93 |
|
|
|
|
|
OP_SUB = 0x94 |
|
|
|
|
|
OP_MUL = 0x95 |
|
|
|
|
|
OP_DIV = 0x96 |
|
|
|
|
|
OP_MOD = 0x97 |
|
|
|
|
|
OP_LSHIFT = 0x98 |
|
|
|
|
|
OP_RSHIFT = 0x99 |
|
|
|
|
|
|
|
|
|
|
|
OP_BOOLAND = 0x9a |
|
|
|
|
|
OP_BOOLOR = 0x9b |
|
|
|
|
|
OP_NUMEQUAL = 0x9c |
|
|
|
|
|
OP_NUMEQUALVERIFY = 0x9d |
|
|
|
|
|
OP_NUMNOTEQUAL = 0x9e |
|
|
|
|
|
OP_LESSTHAN = 0x9f |
|
|
|
|
|
OP_GREATERTHAN = 0xa0 |
|
|
|
|
|
OP_LESSTHANOREQUAL = 0xa1 |
|
|
|
|
|
OP_GREATERTHANOREQUAL = 0xa2 |
|
|
|
|
|
OP_MIN = 0xa3 |
|
|
|
|
|
OP_MAX = 0xa4 |
|
|
|
|
|
|
|
|
|
|
|
OP_WITHIN = 0xa5 |
|
|
|
|
|
|
|
|
|
|
|
# crypto |
|
|
|
|
|
OP_RIPEMD160 = 0xa6 |
|
|
|
|
|
OP_SHA1 = 0xa7 |
|
|
|
|
|
OP_SHA256 = 0xa8 |
|
|
|
|
|
OP_HASH160 = 0xa9 |
|
|
|
|
|
OP_HASH256 = 0xaa |
|
|
|
|
|
OP_CODESEPARATOR = 0xab |
|
|
|
|
|
OP_CHECKSIG = 0xac |
|
|
|
|
|
OP_CHECKSIGVERIFY = 0xad |
|
|
|
|
|
OP_CHECKMULTISIG = 0xae |
|
|
|
|
|
OP_CHECKMULTISIGVERIFY = 0xaf |
|
|
|
|
|
|
|
|
|
|
|
# expansion |
|
|
|
|
|
OP_NOP1 = 0xb0 |
|
|
|
|
|
OP_CHECKLOCKTIMEVERIFY = 0xb1 |
|
|
|
|
|
OP_NOP2 = OP_CHECKLOCKTIMEVERIFY |
|
|
|
|
|
OP_CHECKSEQUENCEVERIFY = 0xb2 |
|
|
|
|
|
OP_NOP3 = OP_CHECKSEQUENCEVERIFY |
|
|
|
|
|
OP_NOP4 = 0xb3 |
|
|
|
|
|
OP_NOP5 = 0xb4 |
|
|
|
|
|
OP_NOP6 = 0xb5 |
|
|
|
|
|
OP_NOP7 = 0xb6 |
|
|
|
|
|
OP_NOP8 = 0xb7 |
|
|
|
|
|
OP_NOP9 = 0xb8 |
|
|
|
|
|
OP_NOP10 = 0xb9 |
|
|
|
|
|
|
|
|
|
|
|
OP_INVALIDOPCODE = 0xff |
|
|
|
|
|
|
|
|
|
|
|
def hex(self) -> str: |
|
|
|
|
|
return bytes([self]).hex() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rev_hex(s: str) -> str: |
|
|
def rev_hex(s: str) -> str: |
|
|
return bh2u(bfh(s)[::-1]) |
|
|
return bh2u(bfh(s)[::-1]) |
|
|
|
|
|
|
|
@ -112,15 +254,15 @@ def witness_push(item: str) -> str: |
|
|
return var_int(len(item) // 2) + item |
|
|
return var_int(len(item) // 2) + item |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def op_push(i: int) -> str: |
|
|
def _op_push(i: int) -> str: |
|
|
if i<0x4c: # OP_PUSHDATA1 |
|
|
if i < opcodes.OP_PUSHDATA1: |
|
|
return int_to_hex(i) |
|
|
return int_to_hex(i) |
|
|
elif i<=0xff: |
|
|
elif i <= 0xff: |
|
|
return '4c' + int_to_hex(i) |
|
|
return opcodes.OP_PUSHDATA1.hex() + int_to_hex(i, 1) |
|
|
elif i<=0xffff: |
|
|
elif i <= 0xffff: |
|
|
return '4d' + int_to_hex(i,2) |
|
|
return opcodes.OP_PUSHDATA2.hex() + int_to_hex(i, 2) |
|
|
else: |
|
|
else: |
|
|
return '4e' + int_to_hex(i,4) |
|
|
return opcodes.OP_PUSHDATA4.hex() + int_to_hex(i, 4) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def push_script(data: str) -> str: |
|
|
def push_script(data: str) -> str: |
|
@ -131,19 +273,17 @@ def push_script(data: str) -> str: |
|
|
ported from https://github.com/btcsuite/btcd/blob/fdc2bc867bda6b351191b5872d2da8270df00d13/txscript/scriptbuilder.go#L128 |
|
|
ported from https://github.com/btcsuite/btcd/blob/fdc2bc867bda6b351191b5872d2da8270df00d13/txscript/scriptbuilder.go#L128 |
|
|
""" |
|
|
""" |
|
|
data = bfh(data) |
|
|
data = bfh(data) |
|
|
from .transaction import opcodes |
|
|
|
|
|
|
|
|
|
|
|
data_len = len(data) |
|
|
data_len = len(data) |
|
|
|
|
|
|
|
|
# "small integer" opcodes |
|
|
# "small integer" opcodes |
|
|
if data_len == 0 or data_len == 1 and data[0] == 0: |
|
|
if data_len == 0 or data_len == 1 and data[0] == 0: |
|
|
return bh2u(bytes([opcodes.OP_0])) |
|
|
return opcodes.OP_0.hex() |
|
|
elif data_len == 1 and data[0] <= 16: |
|
|
elif data_len == 1 and data[0] <= 16: |
|
|
return bh2u(bytes([opcodes.OP_1 - 1 + data[0]])) |
|
|
return bh2u(bytes([opcodes.OP_1 - 1 + data[0]])) |
|
|
elif data_len == 1 and data[0] == 0x81: |
|
|
elif data_len == 1 and data[0] == 0x81: |
|
|
return bh2u(bytes([opcodes.OP_1NEGATE])) |
|
|
return opcodes.OP_1NEGATE.hex() |
|
|
|
|
|
|
|
|
return op_push(data_len) + bh2u(data) |
|
|
return _op_push(data_len) + bh2u(data) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_number_to_script(i: int) -> bytes: |
|
|
def add_number_to_script(i: int) -> bytes: |
|
@ -305,19 +445,18 @@ def address_to_script(addr: str, *, net=None) -> str: |
|
|
if witprog is not None: |
|
|
if witprog is not None: |
|
|
if not (0 <= witver <= 16): |
|
|
if not (0 <= witver <= 16): |
|
|
raise BitcoinException(f'impossible witness version: {witver}') |
|
|
raise BitcoinException(f'impossible witness version: {witver}') |
|
|
OP_n = witver + 0x50 if witver > 0 else 0 |
|
|
script = bh2u(add_number_to_script(witver)) |
|
|
script = bh2u(bytes([OP_n])) |
|
|
|
|
|
script += push_script(bh2u(bytes(witprog))) |
|
|
script += push_script(bh2u(bytes(witprog))) |
|
|
return script |
|
|
return script |
|
|
addrtype, hash_160_ = b58_address_to_hash160(addr) |
|
|
addrtype, hash_160_ = b58_address_to_hash160(addr) |
|
|
if addrtype == net.ADDRTYPE_P2PKH: |
|
|
if addrtype == net.ADDRTYPE_P2PKH: |
|
|
script = '76a9' # op_dup, op_hash_160 |
|
|
script = bytes([opcodes.OP_DUP, opcodes.OP_HASH160]).hex() |
|
|
script += push_script(bh2u(hash_160_)) |
|
|
script += push_script(bh2u(hash_160_)) |
|
|
script += '88ac' # op_equalverify, op_checksig |
|
|
script += bytes([opcodes.OP_EQUALVERIFY, opcodes.OP_CHECKSIG]).hex() |
|
|
elif addrtype == net.ADDRTYPE_P2SH: |
|
|
elif addrtype == net.ADDRTYPE_P2SH: |
|
|
script = 'a9' # op_hash_160 |
|
|
script = opcodes.OP_HASH160.hex() |
|
|
script += push_script(bh2u(hash_160_)) |
|
|
script += push_script(bh2u(hash_160_)) |
|
|
script += '87' # op_equal |
|
|
script += opcodes.OP_EQUAL.hex() |
|
|
else: |
|
|
else: |
|
|
raise BitcoinException(f'unknown address type: {addrtype}') |
|
|
raise BitcoinException(f'unknown address type: {addrtype}') |
|
|
return script |
|
|
return script |
|
@ -331,9 +470,7 @@ def script_to_scripthash(script: str) -> str: |
|
|
return bh2u(bytes(reversed(h))) |
|
|
return bh2u(bytes(reversed(h))) |
|
|
|
|
|
|
|
|
def public_key_to_p2pk_script(pubkey: str) -> str: |
|
|
def public_key_to_p2pk_script(pubkey: str) -> str: |
|
|
script = push_script(pubkey) |
|
|
return push_script(pubkey) + opcodes.OP_CHECKSIG.hex() |
|
|
script += 'ac' # op_checksig |
|
|
|
|
|
return script |
|
|
|
|
|
|
|
|
|
|
|
__b58chars = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' |
|
|
__b58chars = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' |
|
|
assert len(__b58chars) == 58 |
|
|
assert len(__b58chars) == 58 |
|
|