version 2.0 draft
This commit is contained in:
parent
77ef176e8a
commit
a4050459d9
106
pybtc/address.py
Normal file
106
pybtc/address.py
Normal file
@ -0,0 +1,106 @@
|
||||
from .tools import *
|
||||
|
||||
class PrivateKey():
|
||||
def __init__(self, key=None, compressed=True, testnet=False):
|
||||
if key is None:
|
||||
self.compressed = compressed
|
||||
self.testnet = testnet
|
||||
self.raw_key = create_private_key()
|
||||
else:
|
||||
if type(key) == str:
|
||||
try:
|
||||
key = unhexlify(key)
|
||||
except:
|
||||
pass
|
||||
if type(key) == bytes:
|
||||
assert len(key) == 32
|
||||
self.raw_key = key
|
||||
self.compressed = compressed
|
||||
self.testnet = testnet
|
||||
return
|
||||
assert type(key) == str
|
||||
self.raw_key = WIF_to_private_key(key)
|
||||
if key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
|
||||
TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX):
|
||||
self.compressed = False
|
||||
else:
|
||||
self.compressed = True
|
||||
if key[0] in (TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
|
||||
TESTNET_PRIVATE_KEY_COMPRESSED_PREFIX):
|
||||
self.testnet = True
|
||||
else:
|
||||
self.testnet = False
|
||||
|
||||
def hex(self):
|
||||
return hexlify(self.raw_key).decode()
|
||||
|
||||
def WIF(self, compressed=None, testnet=None):
|
||||
if compressed is None:
|
||||
compressed = self.compressed
|
||||
if testnet is None:
|
||||
testnet = self.testnet
|
||||
return private_key_to_WIF(self.raw_key, compressed, testnet)
|
||||
|
||||
|
||||
class PublicKey():
|
||||
def __init__(self, key=None):
|
||||
if type(key) == str:
|
||||
try:
|
||||
key = unhexlify(key)
|
||||
except:
|
||||
pass
|
||||
if type(key) == PrivateKey:
|
||||
key = private_to_public_key(key.raw_key,
|
||||
compressed=key.compressed)
|
||||
assert type(key) == bytes
|
||||
assert len(key) == 33 or len(key) == 65
|
||||
if len(key) == 33:
|
||||
self.compressed = True
|
||||
else:
|
||||
self.compressed = False
|
||||
self.raw_key = key
|
||||
|
||||
|
||||
def hex(self):
|
||||
return hexlify(self.raw_key).decode()
|
||||
|
||||
|
||||
|
||||
class Address():
|
||||
def __init__(self, key = None,
|
||||
address_type="P2WPKH", testnet=False, compressed = True):
|
||||
if key is None:
|
||||
self.private_key = PrivateKey(testnet = testnet,
|
||||
compressed = compressed)
|
||||
self.public_key = PublicKey(self.private_key)
|
||||
elif type(key) == PrivateKey:
|
||||
self.private_key = key
|
||||
testnet = key.testnet
|
||||
compressed = key.compressed
|
||||
self.public_key = PublicKey(self.private_key)
|
||||
elif type(key) == PublicKey:
|
||||
self.public_key = key
|
||||
testnet = testnet
|
||||
compressed = key.compressed
|
||||
assert address_type in ("P2PKH", "PUBKEY", "P2WPKH", "P2SH_P2WPKH")
|
||||
if not compressed:
|
||||
assert address_type in ("P2PKH", "PUBKEY")
|
||||
self.type = address_type
|
||||
self.testnet = testnet
|
||||
if address_type in ("P2WPKH"):
|
||||
self.witness_version = 0
|
||||
else:
|
||||
self.witness_version = None
|
||||
self.compressed = compressed
|
||||
|
||||
if address_type == "P2SH_P2WPKH":
|
||||
self.script_hash = True
|
||||
self.redeem_script = public_key_to_P2SH_P2WPKH_script(self.public_key.raw_key)
|
||||
self.redeem_script_hex = hexlify(self.redeem_script).decode()
|
||||
self.hash = hash160(self.redeem_script)
|
||||
else:
|
||||
self.script_hash = False
|
||||
self.hash = hash160(self.public_key.raw_key)
|
||||
self.address = hash_to_address(self.hash,
|
||||
script_hash = self.script_hash,
|
||||
witness_version = self.witness_version)
|
||||
0
pybtc/block.py
Normal file
0
pybtc/block.py
Normal file
@ -6,259 +6,10 @@ from .tools import *
|
||||
from .consensus import *
|
||||
from binascii import hexlify, unhexlify
|
||||
|
||||
def get_stream(stream):
|
||||
if type(stream) != io.BytesIO:
|
||||
if type(stream) == str:
|
||||
stream = unhexlify(stream)
|
||||
if type(stream) == bytes:
|
||||
stream = io.BytesIO(stream)
|
||||
else:
|
||||
raise TypeError
|
||||
return stream
|
||||
|
||||
class Opcode():
|
||||
""" Class opcode """
|
||||
def __init__(self, raw_opcode, data, data_length = b""):
|
||||
self.raw = raw_opcode
|
||||
if self.raw in RAW_OPCODE:
|
||||
if self.raw in (OPCODE["OP_PUSHDATA1"], OPCODE["OP_PUSHDATA2"], OPCODE["OP_PUSHDATA4"]):
|
||||
self.str = '<%s>' % len(data)
|
||||
else:
|
||||
self.str = RAW_OPCODE[self.raw]
|
||||
elif self.raw < b'L':
|
||||
self.str = '<%s>' % len(data)
|
||||
else:
|
||||
self.str = '[?]'
|
||||
self.data = data
|
||||
self.data_length = data_length
|
||||
|
||||
def __str__(self):
|
||||
return self.str
|
||||
|
||||
@classmethod
|
||||
def to_raw(cls, name):
|
||||
if name in OPCODE:
|
||||
return OPCODE[name]
|
||||
else:
|
||||
return b''
|
||||
|
||||
@classmethod
|
||||
def pop_from_stream (cls, stream):
|
||||
b = stream.read(1)
|
||||
if not b: return None
|
||||
data = b''
|
||||
data_length = b''
|
||||
if b <= OPCODE["OP_PUSHDATA4"]:
|
||||
if b < OPCODE["OP_PUSHDATA1"]: s = int.from_bytes(b,'little')
|
||||
elif b == OPCODE["OP_PUSHDATA1"]:
|
||||
data_length = stream.read(1)
|
||||
s = int.from_bytes( data_length ,'little')
|
||||
elif b == OPCODE["OP_PUSHDATA2"]:
|
||||
data_length = stream.read(2)
|
||||
s = int.from_bytes( data_length ,'little')
|
||||
elif b == OPCODE["OP_PUSHDATA4"]:
|
||||
data_length = stream.read(4)
|
||||
s = int.from_bytes( data_length ,'little')
|
||||
data = stream.read(s)
|
||||
if len(data)!=s:
|
||||
return None
|
||||
raise Exception('opcode read error')
|
||||
return cls(b,data,data_length)
|
||||
k = 0
|
||||
|
||||
|
||||
|
||||
class Script():
|
||||
"""
|
||||
Bitcoin script class
|
||||
"""
|
||||
def __init__(self, raw_script, coinbase = False, segwit = True):
|
||||
if type(raw_script) == str:
|
||||
raw_script = unhexlify(raw_script)
|
||||
self.raw = raw_script
|
||||
stream = io.BytesIO(raw_script)
|
||||
self.script = []
|
||||
self.address = list()
|
||||
self.pattern = bytearray()
|
||||
self.asm = bytearray()
|
||||
self.data = b''
|
||||
self.type = "NON_STANDARD"
|
||||
self.ntype = 7
|
||||
self.witness_version = None
|
||||
self.op_sig_count = 0
|
||||
if coinbase:
|
||||
self.pattern = b"<coinbase>"
|
||||
self.asm = hexlify(raw_script).decode()
|
||||
return
|
||||
t = time.time()
|
||||
while True:
|
||||
o = Opcode.pop_from_stream(stream)
|
||||
if o is None:
|
||||
break
|
||||
if o.raw == OPCODE["OP_CHECKSIG"] or o.raw == OPCODE["OP_CHECKSIGVERIFY"]:
|
||||
self.op_sig_count += 1
|
||||
if o.raw ==OPCODE["OP_CHECKMULTISIG"]:
|
||||
self.op_sig_count += 20
|
||||
self.script.append(o)
|
||||
self.pattern += o.str.encode() + b' '
|
||||
if o.data:
|
||||
self.asm += hexlify(o.data) + b' '
|
||||
else:
|
||||
self.asm += o.str.encode() + b' '
|
||||
self.asm = self.asm.decode().rstrip()
|
||||
self.pattern= self.pattern.decode().rstrip()
|
||||
# check script type
|
||||
if self.pattern == "OP_DUP OP_HASH160 <20> OP_EQUALVERIFY OP_CHECKSIG":
|
||||
self.type = "P2PKH"
|
||||
self.ntype = 0
|
||||
self.address.append(self.script[2].data)
|
||||
elif self.pattern == "OP_HASH160 <20> OP_EQUAL":
|
||||
self.type = "P2SH"
|
||||
self.ntype = 1
|
||||
self.address.append(self.script[1].data)
|
||||
elif self.pattern == "<65> OP_CHECKSIG" or self.pattern == "<33> OP_CHECKSIG" :
|
||||
self.type = "PUBKEY"
|
||||
self.ntype = 2
|
||||
self.address.append(hash160(self.script[0].data))
|
||||
elif len(self.script) == 2 and self.script[0].raw == OPCODE["OP_RETURN"]:
|
||||
# OP_RETURN
|
||||
if len(self.script[1].data) < NULL_DATA_LIMIT: # <0 to 80 bytes of data>
|
||||
self.data = self.script[1].data
|
||||
self.type = "NULL_DATA"
|
||||
self.ntype = 3
|
||||
elif len(self.script)>= 4:
|
||||
if self.script[-1].raw == OPCODE["OP_CHECKMULTISIG"] \
|
||||
and self.script[-2].raw <= OPCODE["OP_15"] \
|
||||
and self.script[-2].raw >= OPCODE["OP_1"] : # OP_CHECKMULTISIG "OP_1" "OP_16"
|
||||
if self.script[0].raw <= OPCODE["OP_15"] \
|
||||
and self.script[0].raw >= OPCODE["OP_1"]:
|
||||
self.op_sig_count = 0
|
||||
for o in self.script[1:-2]:
|
||||
if not o.data:
|
||||
self.op_sig_count = 20
|
||||
break
|
||||
self.op_sig_count += 1
|
||||
self.address.append(hash160(o.data))
|
||||
else:
|
||||
self.bare_multisig_accepted = ord(self.script[0].raw) - 80
|
||||
self.bare_multisig_from = ord(self.script[-2].raw) - 80
|
||||
self.type = "MULTISIG"
|
||||
self.ntype = 4
|
||||
|
||||
elif segwit:
|
||||
if self.pattern == "OP_0 <20>":
|
||||
self.type = "P2WPKH"
|
||||
self.op_sig_count = 1
|
||||
self.ntype = 5
|
||||
self.witness_version = 0
|
||||
self.address.append(self.script[1].data)
|
||||
elif self.pattern == "OP_0 <32>":
|
||||
self.type = "P2WSH"
|
||||
self.ntype = 6
|
||||
self.witness_version = 0
|
||||
self.address.append(self.script[1].data)
|
||||
|
||||
|
||||
|
||||
class Input:
|
||||
""" Transaction Input class """
|
||||
# outpoint = (b'00f0f09...',n')
|
||||
# script = raw bytes
|
||||
# sequense = int
|
||||
def __init__(self, outpoint, script, sequence, amount = None, private_key = None):
|
||||
if type(outpoint[0]) == str:
|
||||
outpoint = (unhexlify(outpoint[0])[::-1], outpoint[1])
|
||||
if type(outpoint[0]) == str:
|
||||
private_key = WIF2priv(private_key)
|
||||
self.outpoint = outpoint
|
||||
self.sequence = sequence
|
||||
self.pk_script = None
|
||||
self.amount = amount
|
||||
self.private_key = private_key
|
||||
self.p2sh_type = None
|
||||
self.coinbase = False
|
||||
if outpoint == (b'\x00'*32 ,0xffffffff): self.coinbase = True
|
||||
self.sig_script = Script(script, self.coinbase)
|
||||
self.double_spend = None
|
||||
self.lock = False
|
||||
self.addresses = []
|
||||
self.redeem_script = None
|
||||
if len(self.sig_script.script) > 0:
|
||||
try:
|
||||
if len(self.sig_script.script[-1].data) <= 520:
|
||||
self.redeem_script = Script(self.sig_script.script[-1].data)
|
||||
else:
|
||||
pass
|
||||
except Exception as err:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream):
|
||||
stream = get_stream(stream)
|
||||
outpoint = stream.read(32), int.from_bytes(stream.read(4), 'little')
|
||||
script_len = from_var_int(read_var_int(stream))
|
||||
script = stream.read(script_len)
|
||||
sequence = int.from_bytes(stream.read(4), 'little')
|
||||
return cls(outpoint, script, sequence)
|
||||
|
||||
def serialize(self):
|
||||
return self.outpoint[0] + self.outpoint[1].to_bytes(4, 'little') \
|
||||
+ to_var_int(len(self.sig_script.raw)) + self.sig_script.raw \
|
||||
+ self.sequence.to_bytes(4, 'little')
|
||||
|
||||
|
||||
|
||||
class Output:
|
||||
""" Transactin output class """
|
||||
def __init__(self, value, script):
|
||||
self.value = value
|
||||
self.pk_script = Script(script)
|
||||
|
||||
def serialize(self):
|
||||
return self.value.to_bytes(8,'little') \
|
||||
+ to_var_int(len(self.pk_script.raw)) + self.pk_script.raw
|
||||
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream):
|
||||
stream = get_stream(stream)
|
||||
value = int.from_bytes(stream.read(8), 'little')
|
||||
script_len = from_var_int(read_var_int(stream))
|
||||
pk_script = stream.read(script_len)
|
||||
return cls(value, pk_script)
|
||||
|
||||
class Witness:
|
||||
def __init__(self, data, empty = False):
|
||||
self.empty = empty
|
||||
self.witness = [b"\x00"] if empty else data
|
||||
|
||||
def __str__(self):
|
||||
return json.dumps([hexlify(w).decode() for w in self.witness])
|
||||
|
||||
def hex(self):
|
||||
return [hexlify(w).decode() for w in self.witness]
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream):
|
||||
stream = get_stream(stream)
|
||||
empty = True
|
||||
witness_len = from_var_int(read_var_int(stream))
|
||||
witness = []
|
||||
if witness_len:
|
||||
for i in range(witness_len):
|
||||
l = from_var_int(read_var_int(stream))
|
||||
w = stream.read(l)
|
||||
witness.append(w)
|
||||
empty = False
|
||||
return cls(witness, empty)
|
||||
|
||||
def serialize(self):
|
||||
if self.empty:
|
||||
return b'\x00'
|
||||
|
||||
n = to_var_int(len(self.witness))
|
||||
for w in self.witness:
|
||||
n += to_var_int(len(w)) + w
|
||||
return n
|
||||
|
||||
|
||||
class Transaction():
|
||||
@ -306,7 +57,7 @@ class Transaction():
|
||||
if not self.tx_in:
|
||||
self.witness = list()
|
||||
if witness is None:
|
||||
self.witness = [Witness.deserialize(b"\x00") for i in range(len(tx_in))]
|
||||
self.witness = (Witness.deserialize(b"\x00") for i in range(len(tx_in)))
|
||||
if hash is None :
|
||||
self.recalculate_txid()
|
||||
|
||||
@ -376,7 +127,7 @@ class Transaction():
|
||||
if type(p2wpkh_address)==str:
|
||||
assert address_type(p2wpkh_address) == 'P2WPKH'
|
||||
witness_version = get_witness_version(p2wpkh_address)
|
||||
p2wpkh_address = address2hash(p2wpkh_address)
|
||||
p2wpkh_address = address_to_hash(p2wpkh_address)
|
||||
assert len(p2wpkh_address) == 20
|
||||
self.tx_out.append(Output(amount,
|
||||
bytes([witness_version]) + b'\x14' + p2wpkh_address))
|
||||
@ -387,7 +138,7 @@ class Transaction():
|
||||
if type(p2wsh_address)==str:
|
||||
assert address_type(p2wsh_address) == 'P2WSH'
|
||||
witness_version = get_witness_version(p2wsh_address)
|
||||
p2wsh_address = address2hash(p2wsh_address)
|
||||
p2wsh_address = address_to_hash(p2wsh_address)
|
||||
assert len(p2wsh_address) == 32
|
||||
self.tx_out.append(Output(amount,
|
||||
bytes([witness_version]) + b'\x20' + p2wsh_address))
|
||||
@ -427,9 +178,9 @@ class Transaction():
|
||||
|
||||
def serialize(self, segwit = True, hex = False):
|
||||
version = self.version.to_bytes(4,'little')
|
||||
ninputs = to_var_int(self.tx_in_count)
|
||||
ninputs = int_to_var_int(self.tx_in_count)
|
||||
inputs = [i.serialize() for i in self.tx_in]
|
||||
nouts = to_var_int(len(self.tx_out))
|
||||
nouts = int_to_var_int(len(self.tx_out))
|
||||
outputs = [o.serialize() for o in self.tx_out]
|
||||
marke_flag = b"\x00\x01" if segwit else b""
|
||||
witness = b""
|
||||
@ -445,7 +196,7 @@ class Transaction():
|
||||
|
||||
def sign_P2SHP2WPKH_input(self, sighash_type, input_index, private_key = None, amount = None):
|
||||
if type(private_key) == str:
|
||||
private_key = WIF2priv(private_key)
|
||||
private_key = WIF_to_private_key(private_key)
|
||||
if amount is not None:
|
||||
self.tx_in[input_index].amount = amount
|
||||
else:
|
||||
@ -454,7 +205,7 @@ class Transaction():
|
||||
self.tx_in[input_index].private_key = private_key
|
||||
else:
|
||||
private_key = self.tx_in[input_index].private_key
|
||||
pubkey = priv2pub(private_key, True)
|
||||
pubkey = private_to_public_key(private_key, True)
|
||||
pubkey_hash160 = hash160(pubkey)
|
||||
scriptCode = b"\x19" + OPCODE["OP_DUP"] + OPCODE["OP_HASH160"]
|
||||
scriptCode += b'\x14' + pubkey_hash160 + OPCODE["OP_EQUALVERIFY"] + OPCODE["OP_CHECKSIG"]
|
||||
@ -469,7 +220,7 @@ class Transaction():
|
||||
self.tx_in[input_index].private_key = private_key
|
||||
else:
|
||||
private_key = self.tx_in[input_index].private_key
|
||||
pubkey = priv2pub(private_key, compressed)
|
||||
pubkey = private_to_public_key(private_key, compressed)
|
||||
pubkey_hash160 = hash160(pubkey)
|
||||
scriptCode = OPCODE["OP_DUP"] + OPCODE["OP_HASH160"] + b'\x14' + \
|
||||
pubkey_hash160 + OPCODE["OP_EQUALVERIFY"] + OPCODE["OP_CHECKSIG"]
|
||||
@ -489,24 +240,24 @@ class Transaction():
|
||||
if ((sighash_type&31) == SIGHASH_SINGLE) and (input_index>(len(self.tx_out)-1)):
|
||||
return double_sha256(b'\x01'+b'\x00'*31 + sighash_type.to_bytes(4, 'little'))
|
||||
preimage += self.version.to_bytes(4,'little')
|
||||
preimage += b'\x01' if sighash_type & SIGHASH_ANYONECANPAY else to_var_int(self.tx_in_count)
|
||||
preimage += b'\x01' if sighash_type & SIGHASH_ANYONECANPAY else int_to_var_int(self.tx_in_count)
|
||||
for number, i in enumerate(self.tx_in):
|
||||
if (sighash_type & SIGHASH_ANYONECANPAY) and (input_index != number): continue
|
||||
input = i.outpoint[0]+i.outpoint[1].to_bytes(4,'little')
|
||||
if sighash_type == 0 or input_index == number:
|
||||
input += ((to_var_int(len(scriptCode)) + scriptCode) if sighash_type else \
|
||||
(to_var_int(len(i.sig_script.raw)) + i.sig_script.raw)) + i.sequence.to_bytes(4,'little')
|
||||
input += ((int_to_var_int(len(scriptCode)) + scriptCode) if sighash_type else \
|
||||
(int_to_var_int(len(i.sig_script.raw)) + i.sig_script.raw)) + i.sequence.to_bytes(4, 'little')
|
||||
else:
|
||||
input += b'\x00' + (i.sequence.to_bytes(4,'little') if \
|
||||
((sighash_type&31) == SIGHASH_ALL) else b'\x00\x00\x00\x00')
|
||||
preimage += input
|
||||
preimage += b'\x00' if (sighash_type&31) == SIGHASH_NONE else ( to_var_int(input_index + 1) if \
|
||||
(sighash_type&31) == SIGHASH_SINGLE else to_var_int(self.tx_out_count))
|
||||
preimage += b'\x00' if (sighash_type&31) == SIGHASH_NONE else (int_to_var_int(input_index + 1) if \
|
||||
(sighash_type&31) == SIGHASH_SINGLE else int_to_var_int(self.tx_out_count))
|
||||
if (sighash_type&31) != SIGHASH_NONE:
|
||||
for number, i in enumerate(self.tx_out):
|
||||
if number > input_index and (sighash_type&31) == SIGHASH_SINGLE: continue
|
||||
preimage +=(b'\xff'*8+b'\x00' if (sighash_type&31) == SIGHASH_SINGLE and (input_index != number)\
|
||||
else i.value.to_bytes(8,'little')+to_var_int(len(i.pk_script.raw))+i.pk_script.raw)
|
||||
else i.value.to_bytes(8,'little') + int_to_var_int(len(i.pk_script.raw)) + i.pk_script.raw)
|
||||
preimage += self.lock_time.to_bytes(4,'little')
|
||||
preimage += sighash_type.to_bytes(4, 'little')
|
||||
return double_sha256(preimage) if not hex else hexlify(double_sha256(preimage)).decode()
|
||||
@ -543,10 +294,10 @@ class Transaction():
|
||||
ho = bytearray()
|
||||
for n, o in enumerate(self.tx_out):
|
||||
if (sighash_type&31) != SIGHASH_SINGLE and (sighash_type&31) != SIGHASH_NONE:
|
||||
ho += o.value.to_bytes(8,'little')+to_var_int(len(o.pk_script.raw))+o.pk_script.raw
|
||||
ho += o.value.to_bytes(8,'little') + int_to_var_int(len(o.pk_script.raw)) + o.pk_script.raw
|
||||
elif (sighash_type&31) == SIGHASH_SINGLE and input_index < len(self.tx_out):
|
||||
if input_index == n:
|
||||
ho += o.value.to_bytes(8, 'little') + to_var_int(len(o.pk_script.raw)) + o.pk_script.raw
|
||||
ho += o.value.to_bytes(8, 'little') + int_to_var_int(len(o.pk_script.raw)) + o.pk_script.raw
|
||||
hashOutputs = double_sha256(ho) if ho else b'\x00'*32
|
||||
preimage += hashPrevouts + hashSequence + outpoint + scriptCode + value + nSequence + hashOutputs
|
||||
preimage += self.lock_time.to_bytes(4, 'little')
|
||||
@ -589,10 +340,10 @@ class Transaction():
|
||||
if o.pk_script.ntype in (1,6):
|
||||
sh =True
|
||||
for a in o.pk_script.address:
|
||||
out["address"].append(hash2address(a,
|
||||
testnet=testnet,
|
||||
script_hash= sh,
|
||||
witness_version=o.pk_script.witness_version))
|
||||
out["address"].append(hash_to_address(a,
|
||||
testnet=testnet,
|
||||
script_hash= sh,
|
||||
witness_version=o.pk_script.witness_version))
|
||||
|
||||
r["vout"].append(out)
|
||||
|
||||
@ -662,6 +413,7 @@ class Transaction():
|
||||
class Block():
|
||||
def __init__(self, version, prev_block, merkle_root,
|
||||
timestamp, bits, nonce, txs, block_size, hash = None, header = None):
|
||||
qt = time.time()
|
||||
self.hash = hash
|
||||
self.header = header
|
||||
self.version = version
|
||||
@ -671,6 +423,7 @@ class Block():
|
||||
self.timestamp = timestamp
|
||||
self.bits = bits
|
||||
self.nonce = nonce
|
||||
|
||||
self.transactions = txs
|
||||
self.tx_hash_list = list()
|
||||
self.size = block_size
|
||||
@ -679,13 +432,12 @@ class Block():
|
||||
self.amount = 0
|
||||
self.fee = 0
|
||||
self.sigop = 0
|
||||
for t in txs:
|
||||
if t.hash in self.tx_hash_list:
|
||||
raise Exception("CVE-2012-2459") # merkle tree malleability
|
||||
self.tx_hash_list.append(t.hash)
|
||||
|
||||
|
||||
self.target = None
|
||||
self.fee = 0
|
||||
self.witness_root_hash = None
|
||||
|
||||
if txs:
|
||||
if txs[0].coinbase:
|
||||
if self.nversion > 1:
|
||||
@ -700,6 +452,7 @@ class Block():
|
||||
self.witness_root_hash = out.pk_script.data[4:36]
|
||||
except:
|
||||
pass
|
||||
print("t ", time.time() - qt)
|
||||
|
||||
def calculate_commitment(self, witness = None):
|
||||
wtxid_list = [b"\x00" * 32,]
|
||||
@ -723,7 +476,7 @@ class Block():
|
||||
commitment = self.calculate_commitment(tx.witness[0].witness[0])
|
||||
for o in outputs:
|
||||
if type(o[1]) == str:
|
||||
tx.tx_out.append(Output(o[0], address2script(o[1])))
|
||||
tx.tx_out.append(Output(o[0], address_to_script(o[1])))
|
||||
else:
|
||||
tx.tx_out.append(Output(o[0], o[1]))
|
||||
tx.tx_out.append(Output(0, b'j$\xaa!\xa9\xed' + commitment))
|
||||
@ -762,11 +515,14 @@ class Block():
|
||||
'merkle_root': stream.read(32),
|
||||
'timestamp': int.from_bytes(stream.read(4), 'little'),
|
||||
'bits': stream.read(4),
|
||||
'nonce': stream.read(4),
|
||||
'txs': read_var_list(stream, Transaction),
|
||||
'block_size': stream.tell(),
|
||||
'header': header
|
||||
}
|
||||
'nonce': stream.read(4)}
|
||||
t = time.time()
|
||||
kwargs['txs'] = read_var_list(stream, Transaction)
|
||||
print("tx ",time.time() - t)
|
||||
kwargs['block_size'] = stream.tell()
|
||||
kwargs['header'] = header
|
||||
global k
|
||||
print(">.>.>.",k)
|
||||
return cls(**kwargs)
|
||||
|
||||
def serialize(self, hex = False):
|
||||
@ -776,13 +532,12 @@ class Block():
|
||||
self.timestamp.to_bytes(4,'little') + \
|
||||
self.bits + \
|
||||
self.nonce + \
|
||||
to_var_int(len (self.transactions))
|
||||
int_to_var_int(len (self.transactions))
|
||||
for t in self.transactions:
|
||||
if t.hash == t.whash:
|
||||
block += t.serialize(segwit = 0)
|
||||
else:
|
||||
block += t.serialize(segwit = 1)
|
||||
|
||||
if hex:
|
||||
return hexlify(block).decode()
|
||||
else:
|
||||
@ -820,8 +575,8 @@ class BlockTemplate():
|
||||
self.scan_tx_list()
|
||||
self.coinbase_tx = self.create_coinbase_transaction()
|
||||
self.coinb1, self.coinb2 = self.split_coinbase()
|
||||
self.target = bits2target(self.bits)
|
||||
self.difficulty = target2difficulty(self.target)
|
||||
self.target = bits_to_target(self.bits)
|
||||
self.difficulty = target_to_difficulty(self.target)
|
||||
self.merkle_branches = [hexlify(i).decode() for i in merkle_branches([self.coinbase_tx.hash,] + self.txid_list)]
|
||||
|
||||
|
||||
@ -906,7 +661,7 @@ class BlockTemplate():
|
||||
print("branches ", self.merkle_branches)
|
||||
header = version + prev_hash + merkle_root + time + bits + nonce
|
||||
block = hexlify(header).decode()
|
||||
block += hexlify(to_var_int(len (self.transactions)+1)).decode()
|
||||
block += hexlify(int_to_var_int(len (self.transactions) + 1)).decode()
|
||||
block += cb
|
||||
for t in self.transactions:
|
||||
block += t["data"]
|
||||
|
||||
@ -74,3 +74,4 @@ SCRIPT_TYPES = { "P2PKH": 0,
|
||||
"NON_STANDART": 7
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -14,8 +14,6 @@ for n, i in enumerate(base32charset_upcase):
|
||||
int_base32_map[i] = n
|
||||
|
||||
|
||||
|
||||
|
||||
def rebasebits(data, frombits, tobits, pad=True):
|
||||
"""General power-of-2 base conversion."""
|
||||
acc = 0
|
||||
|
||||
@ -16,7 +16,6 @@ def double_sha256(h, hex = False):
|
||||
return sha256(sha256(h), 1)
|
||||
return sha256(sha256(h))
|
||||
|
||||
|
||||
def hmac_sha512(key, data, hex = False):
|
||||
if hex:
|
||||
return hmac.new(key, data, hashlib.sha512).hexdigest()
|
||||
|
||||
297
pybtc/opcodes.py
297
pybtc/opcodes.py
@ -1,148 +1,155 @@
|
||||
from binascii import hexlify
|
||||
|
||||
OPCODE = dict()
|
||||
|
||||
# push opcodes
|
||||
|
||||
OPCODE["OP_FALSE"] = 0x00
|
||||
OPCODE["OP_0"] = 0x00
|
||||
OPCODE["OP_PUSHDATA1"] = 0x4c
|
||||
OPCODE["OP_PUSHDATA2"] = 0x4d
|
||||
OPCODE["OP_PUSHDATA4"] = 0x4e
|
||||
OPCODE["OP_1NEGATE"] = 0x4f
|
||||
OPCODE["OP_RESERVED"] = 0x50
|
||||
OPCODE["OP_1"] = 0x51
|
||||
OPCODE["OP_TRUE"] = 0x51
|
||||
OPCODE["OP_2"] = 0x52
|
||||
OPCODE["OP_3"] = 0x53
|
||||
OPCODE["OP_4"] = 0x54
|
||||
OPCODE["OP_5"] = 0x55
|
||||
OPCODE["OP_6"] = 0x56
|
||||
OPCODE["OP_7"] = 0x57
|
||||
OPCODE["OP_8"] = 0x58
|
||||
OPCODE["OP_9"] = 0x59
|
||||
OPCODE["OP_10"] = 0x5a
|
||||
OPCODE["OP_11"] = 0x5b
|
||||
OPCODE["OP_12"] = 0x5c
|
||||
OPCODE["OP_13"] = 0x5d
|
||||
OPCODE["OP_14"] = 0x5e
|
||||
OPCODE["OP_15"] = 0x5f
|
||||
OPCODE["OP_16"] = 0x60
|
||||
|
||||
# control
|
||||
|
||||
OPCODE["OP_NOP"] = 0x61
|
||||
OPCODE["OP_VER"] = 0x62
|
||||
OPCODE["OP_IF"] = 0x63
|
||||
OPCODE["OP_NOTIF"] = 0x64
|
||||
OPCODE["OP_VERIF"] = 0x65
|
||||
OPCODE["OP_ELSE"] = 0x67
|
||||
OPCODE["OP_ENDIF"] = 0x68
|
||||
OPCODE["OP_VERIFY"] = 0x69
|
||||
OPCODE["OP_RETURN"] = 0x6a
|
||||
|
||||
# stack
|
||||
|
||||
OPCODE["OP_TOALTSTACK"] = 0x6b
|
||||
OPCODE["OP_FROMALTSTACK"] = 0x6c
|
||||
OPCODE["OP_2DROP"] = 0x6d
|
||||
OPCODE["OP_2DUP"] = 0x6e
|
||||
OPCODE["OP_3DUP"] = 0x6f
|
||||
OPCODE["OP_2OVER"] = 0x70
|
||||
OPCODE["OP_2ROT"] = 0x71
|
||||
OPCODE["OP_2SWAP"] = 0x72
|
||||
OPCODE["OP_IFDUP"] = 0x73
|
||||
OPCODE["OP_DEPTH"] = 0x74
|
||||
OPCODE["OP_DROP"] = 0x75
|
||||
OPCODE["OP_DUP"] = 0x76
|
||||
OPCODE["OP_NIP"] = 0x77
|
||||
OPCODE["OP_OVER"] = 0x78
|
||||
OPCODE["OP_PICK"] = 0x79
|
||||
OPCODE["OP_ROLL"] = 0x7a
|
||||
OPCODE["OP_ROT"] = 0x7b
|
||||
OPCODE["OP_SWAP"] = 0x7c
|
||||
OPCODE["OP_TUCK"] = 0x7d
|
||||
|
||||
# splice
|
||||
|
||||
OPCODE["OP_CAT"] = 0x7e
|
||||
OPCODE["OP_SUBSTR"] = 0x7f
|
||||
OPCODE["OP_LEFT"] = 0x80
|
||||
OPCODE["OP_RIGHT"] = 0x81
|
||||
OPCODE["OP_SIZE"] = 0x82
|
||||
|
||||
# bit operations
|
||||
|
||||
OPCODE["OP_INVERT"] = 0x83
|
||||
OPCODE["OP_AND"] = 0x84
|
||||
OPCODE["OP_OR"] = 0x85
|
||||
OPCODE["OP_XOR"] = 0x86
|
||||
OPCODE["OP_EQUAL"] = 0x87
|
||||
OPCODE["OP_EQUALVERIFY"] = 0x88
|
||||
OPCODE["OP_RESERVED1"] = 0x89
|
||||
OPCODE["OP_RESERVED2"] = 0x8a
|
||||
|
||||
# math
|
||||
|
||||
OPCODE["OP_1ADD"] = 0x8b
|
||||
OPCODE["OP_1SUB"] = 0x8c
|
||||
OPCODE["OP_2MUL"] = 0x8d
|
||||
OPCODE["OP_2DIV"] = 0x8e
|
||||
OPCODE["OP_NEGATE"] = 0x8f
|
||||
OPCODE["OP_ABS"] = 0x90
|
||||
OPCODE["OP_NOT"] = 0x91
|
||||
OPCODE["OP_0NOTEQUAL"] = 0x92
|
||||
|
||||
OPCODE["OP_ADD"] = 0x93
|
||||
OPCODE["OP_SUB"] = 0x94
|
||||
OPCODE["OP_MUL"] = 0x95
|
||||
OPCODE["OP_DIV"] = 0x96
|
||||
OPCODE["OP_MOD"] = 0x97
|
||||
OPCODE["OP_LSHIFT"] = 0x98
|
||||
OPCODE["OP_RSHIFT"] = 0x99
|
||||
|
||||
OPCODE["OP_BOOLAND"] = 0x9a
|
||||
OPCODE["OP_BOOLOR"] = 0x9b
|
||||
OPCODE["OP_NUMEQUAL"] = 0x9c
|
||||
OPCODE["OP_NUMEQUALVERIFY"] = 0x9d
|
||||
OPCODE["OP_NUMNOTEQUAL"] = 0x9e
|
||||
OPCODE["OP_LESSTHAN"] = 0x9f
|
||||
OPCODE["OP_GREATERTHAN"] = 0xa0
|
||||
OPCODE["OP_LESSTHANOREQUAL"] = 0xa1
|
||||
OPCODE["OP_GREATERTHANOREQUAL"] = 0xa2
|
||||
OPCODE["OP_MIN"] = 0xa3
|
||||
OPCODE["OP_MAX"] = 0xa4
|
||||
|
||||
OPCODE["OP_WITHIN"] = 0xa5
|
||||
|
||||
# crypto
|
||||
|
||||
OPCODE["OP_RIPEMD160"] = 0xa6
|
||||
OPCODE["OP_SHA1"] = 0xa7
|
||||
OPCODE["OP_SHA256"] = 0xa8
|
||||
OPCODE["OP_HASH160"] = 0xa9
|
||||
OPCODE["OP_HASH256"] = 0xaa
|
||||
OPCODE["OP_CODESEPARATOR"] = 0xab
|
||||
OPCODE["OP_CHECKSIG"] = 0xac
|
||||
OPCODE["OP_CHECKSIGVERIFY"] = 0xad
|
||||
OPCODE["OP_CHECKMULTISIG"] = 0xae
|
||||
OPCODE["OP_CHECKMULTISIGVERIFY"] = 0xaf
|
||||
|
||||
# expansion
|
||||
|
||||
OPCODE["OP_NOP1"] = 0xb0
|
||||
OPCODE["OP_CHECKLOCKTIMEVERIFY"] = 0xb1
|
||||
OPCODE["OP_CHECKSEQUENCEVERIFY"] = 0xb2
|
||||
OPCODE["OP_NOP4"] = 0xb3
|
||||
OPCODE["OP_NOP5"] = 0xb4
|
||||
OPCODE["OP_NOP6"] = 0xb5
|
||||
OPCODE["OP_NOP7"] = 0xb6
|
||||
OPCODE["OP_NOP8"] = 0xb7
|
||||
OPCODE["OP_NOP9"] = 0xb8
|
||||
OPCODE["OP_NOP10"] = 0xb9
|
||||
|
||||
# template matching params
|
||||
|
||||
OPCODE["OP_SMALLINTEGER"] = 0xfa
|
||||
OPCODE["OP_PUBKEYS"] = 0xfb
|
||||
OPCODE["OP_PUBKEYHASH"] = 0xfd
|
||||
OPCODE["OP_PUBKEY"] = 0xfe
|
||||
OPCODE["OP_INVALIDOPCODE"] = 0xff
|
||||
|
||||
OPCODE = {"OP_0": b'\x00',
|
||||
"OP_PUSHDATA1": b'L',
|
||||
"OP_PUSHDATA2": b'M',
|
||||
"OP_PUSHDATA4": b'N',
|
||||
"OP_1NEGATE": b'O',
|
||||
"OP_RESERVED": b'P',
|
||||
"OP_1": b'Q',
|
||||
"OP_2": b'R',
|
||||
"OP_3": b'S',
|
||||
"OP_4": b'T',
|
||||
"OP_5": b'U',
|
||||
"OP_6": b'V',
|
||||
"OP_7": b'W',
|
||||
"OP_8": b'X',
|
||||
"OP_9": b'Y',
|
||||
"OP_10": b'Z',
|
||||
"OP_11": b'[',
|
||||
"OP_12": b'\\',
|
||||
"OP_13": b']',
|
||||
"OP_14": b'^',
|
||||
"OP_15": b'_',
|
||||
"OP_16": b'`',
|
||||
"OP_NOP": b'a',
|
||||
"OP_VER": b'b',
|
||||
"OP_IF": b'c',
|
||||
"OP_NOTIF": b'd',
|
||||
"OP_VERIF": b'e',
|
||||
"OP_VERNOTIF": b'f',
|
||||
"OP_ELSE": b'g',
|
||||
"OP_ENDIF": b'h',
|
||||
"OP_VERIFY": b'i',
|
||||
"OP_RETURN": b'j',
|
||||
"OP_TOALTSTACK": b'k',
|
||||
"OP_FROMALTSTACK": b'l',
|
||||
"OP_2DROP": b'm',
|
||||
"OP_2DUP": b'n',
|
||||
"OP_3DUP": b'o',
|
||||
"OP_2OVER": b'p',
|
||||
"OP_2ROT": b'q',
|
||||
"OP_2SWAP": b'r',
|
||||
"OP_IFDUP": b's',
|
||||
"OP_DEPTH": b't',
|
||||
"OP_DROP": b'u',
|
||||
"OP_DUP": b'v',
|
||||
"OP_NIP": b'w',
|
||||
"OP_OVER": b'x',
|
||||
"OP_PICK": b'y',
|
||||
"OP_ROLL": b'z',
|
||||
"OP_ROT": b'{',
|
||||
"OP_SWAP": b'|',
|
||||
"OP_TUCK": b'}',
|
||||
"OP_CAT": b'~',
|
||||
"OP_SUBSTR": b'\x7f',
|
||||
"OP_LEFT": b'\x80',
|
||||
"OP_RIGHT": b'\x81',
|
||||
"OP_SIZE": b'\x82',
|
||||
"OP_INVERT": b'\x83',
|
||||
"OP_AND": b'\x84',
|
||||
"OP_OR": b'\x85',
|
||||
"OP_XOR": b'\x86',
|
||||
"OP_EQUAL": b'\x87',
|
||||
"OP_EQUALVERIFY": b'\x88',
|
||||
"OP_RESERVED1": b'\x89',
|
||||
"OP_RESERVED2": b'\x8a',
|
||||
"OP_1ADD": b'\x8b',
|
||||
"OP_1SUB": b'\x8c',
|
||||
"OP_2MUL": b'\x8d',
|
||||
"OP_2DIV": b'\x8e',
|
||||
"OP_NEGATE": b'\x8f',
|
||||
"OP_ABS": b'\x90',
|
||||
"OP_NOT": b'\x91',
|
||||
"OP_0NOTEQUAL": b'\x92',
|
||||
"OP_ADD": b'\x93',
|
||||
"OP_SUB": b'\x94',
|
||||
"OP_MUL": b'\x95',
|
||||
"OP_DIV": b'\x96',
|
||||
"OP_MOD": b'\x97',
|
||||
"OP_LSHIFT": b'\x98',
|
||||
"OP_RSHIFT": b'\x99',
|
||||
"OP_BOOLAND": b'\x9a',
|
||||
"OP_BOOLOR": b'\x9b',
|
||||
"OP_NUMEQUAL": b'\x9c',
|
||||
"OP_NUMEQUALVERIFY": b'\x9d',
|
||||
"OP_NUMNOTEQUAL": b'\x9e',
|
||||
"OP_LESSTHAN": b'\x9f',
|
||||
"OP_GREATERTHAN": b'\xa0',
|
||||
"OP_LESSTHANOREQUAL": b'\xa1',
|
||||
"OP_GREATERTHANOREQUAL": b'\xa2',
|
||||
"OP_MIN": b'\xa3',
|
||||
"OP_MAX": b'\xa4',
|
||||
"OP_WITHIN": b'\xa5',
|
||||
"OP_RIPEMD160": b'\xa6',
|
||||
"OP_SHA1": b'\xa7',
|
||||
"OP_SHA256": b'\xa8',
|
||||
"OP_HASH160": b'\xa9',
|
||||
"OP_HASH256": b'\xaa',
|
||||
"OP_CODESEPARATOR": b'\xab',
|
||||
"OP_CHECKSIG": b'\xac',
|
||||
"OP_CHECKSIGVERIFY": b'\xad',
|
||||
"OP_CHECKMULTISIG": b'\xae',
|
||||
"OP_CHECKMULTISIGVERIFY": b'\xaf',
|
||||
"OP_NOP1": b'\xb0',
|
||||
"OP_NOP2": b'\xb1',
|
||||
"OP_NOP3": b'\xb2',
|
||||
"OP_NOP4": b'\xb3',
|
||||
"OP_NOP5": b'\xb4',
|
||||
"OP_NOP6": b'\xb5',
|
||||
"OP_NOP7": b'\xb6',
|
||||
"OP_NOP8": b'\xb7',
|
||||
"OP_NOP9": b'\xb8',
|
||||
"OP_NOP10": b'\xb9',
|
||||
"OP_NULLDATA": b'\xfc',
|
||||
"OP_PUBKEYHASH": b'\xfd',
|
||||
"OP_PUBKEY": b'\xfe',
|
||||
"OP_INVALIDOPCODE": b'\xff'}
|
||||
|
||||
RAW_OPCODE = dict ( (OPCODE[i], i) for i in OPCODE )
|
||||
|
||||
DISABLED_OPCODE = set ((
|
||||
# OPCODE["OP_RETURN"],
|
||||
OPCODE["OP_CAT"],
|
||||
OPCODE["OP_SUBSTR"],
|
||||
OPCODE["OP_LEFT"],
|
||||
OPCODE["OP_RIGHT"],
|
||||
OPCODE["OP_LEFT"],
|
||||
OPCODE["OP_LEFT"],
|
||||
OPCODE["OP_AND"],
|
||||
OPCODE["OP_OR"],
|
||||
OPCODE["OP_XOR"],
|
||||
OPCODE["OP_2MUL"],
|
||||
OPCODE["OP_2DIV"],
|
||||
OPCODE["OP_MUL"],
|
||||
OPCODE["OP_DIV"],
|
||||
OPCODE["OP_MOD"],
|
||||
OPCODE["OP_LSHIFT"],
|
||||
OPCODE["OP_RSHIFT"],
|
||||
OPCODE["OP_RESERVED"],
|
||||
# OPCODE["OP_VER"],
|
||||
OPCODE["OP_VERIF"],
|
||||
OPCODE["OP_VERNOTIF"],
|
||||
OPCODE["OP_RESERVED1"],
|
||||
OPCODE["OP_RESERVED2"],
|
||||
OPCODE["OP_PUBKEYHASH"],
|
||||
OPCODE["OP_PUBKEY"],
|
||||
OPCODE["OP_INVALIDOPCODE"]
|
||||
))
|
||||
|
||||
BYTE_OPCODE = dict ((i,bytes([OPCODE[i]])) for i in OPCODE )
|
||||
HEX_OPCODE = dict ((i,hexlify(bytes([OPCODE[i]])).decode()) for i in OPCODE )
|
||||
|
||||
401
pybtc/tools.py
401
pybtc/tools.py
@ -1,23 +1,20 @@
|
||||
import hashlib
|
||||
from binascii import hexlify, unhexlify
|
||||
import time
|
||||
import struct
|
||||
import hmac
|
||||
from .constants import *
|
||||
from .opcodes import *
|
||||
from .hash import *
|
||||
from .encode import *
|
||||
import math
|
||||
import io
|
||||
|
||||
|
||||
# Bitcoin keys/ addresses
|
||||
# Bitcoin keys
|
||||
#
|
||||
def create_priv(hex=False):
|
||||
def create_private_key(hex=False):
|
||||
"""
|
||||
:return: 32 bytes private key
|
||||
"""
|
||||
q = time.time()
|
||||
rnd = random.SystemRandom()
|
||||
a = rnd.randint(0,MAX_INT_PRIVATE_KEY)
|
||||
a = random.SystemRandom().randint(0,MAX_INT_PRIVATE_KEY)
|
||||
i = int((time.time()%0.01)*100000)
|
||||
h = a.to_bytes(32,byteorder="big")
|
||||
while True:
|
||||
@ -30,15 +27,12 @@ def create_priv(hex=False):
|
||||
return hexlify(h).decode()
|
||||
return h
|
||||
|
||||
def priv_from_int(k):
|
||||
return int.to_bytes(k,byteorder="big",length=32)
|
||||
|
||||
|
||||
def priv2WIF(h, compressed = True, testnet = False):
|
||||
def private_key_to_WIF(h, compressed = True, testnet = False):
|
||||
#uncompressed: 0x80 + [32-byte secret] + [4 bytes of Hash() of previous 33 bytes], base58 encoded
|
||||
#compressed: 0x80 + [32-byte secret] + 0x01 + [4 bytes of Hash() previous 34 bytes], base58 encoded
|
||||
if type(h) == str:
|
||||
h = unhexlify(h)
|
||||
assert len(h) == 32
|
||||
if testnet:
|
||||
h = TESTNET_PRIVATE_KEY_BYTE_PREFIX + h
|
||||
else:
|
||||
@ -47,15 +41,15 @@ def priv2WIF(h, compressed = True, testnet = False):
|
||||
h += double_sha256(h)[:4]
|
||||
return encode_base58(h)
|
||||
|
||||
def WIF2priv(h, hex = False, verify = 1):
|
||||
if verify:
|
||||
assert is_WIF_valid(h)
|
||||
def WIF_to_private_key(h, hex = False):
|
||||
assert is_WIF_valid(h)
|
||||
h = decode_base58(h)
|
||||
if hex:
|
||||
return hexlify(h[1:33]).decode()
|
||||
return h[1:33]
|
||||
|
||||
def is_WIF_valid(wif):
|
||||
assert type(wif) == str
|
||||
if wif[0] not in PRIVATE_KEY_PREFIX_LIST:
|
||||
return False
|
||||
try:
|
||||
@ -73,7 +67,7 @@ def is_WIF_valid(wif):
|
||||
return False
|
||||
return True
|
||||
|
||||
def priv2pub(private_key, compressed = True, hex = False):
|
||||
def private_to_public_key(private_key, compressed = True, hex = False):
|
||||
if type(private_key)!= bytes:
|
||||
if type(private_key) == bytearray:
|
||||
private_key = bytes(private_key)
|
||||
@ -84,7 +78,7 @@ def priv2pub(private_key, compressed = True, hex = False):
|
||||
if private_key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
|
||||
TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX):
|
||||
compressed = False
|
||||
private_key = WIF2priv(private_key, verify=0)
|
||||
private_key = WIF_to_private_key(private_key)
|
||||
else:
|
||||
raise TypeError("private key must be a bytes or WIF or hex encoded string")
|
||||
pubkey_ptr = ffi.new('secp256k1_pubkey *')
|
||||
@ -99,7 +93,7 @@ def priv2pub(private_key, compressed = True, hex = False):
|
||||
pub = bytes(ffi.buffer(pubkey, len_key))
|
||||
return hexlify(pub).decode() if hex else pub
|
||||
|
||||
def is_valid_pub(key):
|
||||
def is_valid_public_key(key):
|
||||
if len(key) < 33:
|
||||
return False
|
||||
if key[0] == 0x04 and len(key) != 65:
|
||||
@ -115,8 +109,8 @@ def is_valid_pub(key):
|
||||
#
|
||||
|
||||
|
||||
def hash2address(address_hash, testnet = False,
|
||||
script_hash = False, witness_version = 0):
|
||||
def hash_to_address(address_hash, testnet = False,
|
||||
script_hash = False, witness_version = 0):
|
||||
if type(address_hash) == str:
|
||||
address_hash = unhexlify(address_hash)
|
||||
if not script_hash:
|
||||
@ -151,7 +145,7 @@ def hash2address(address_hash, testnet = False,
|
||||
return "%s1%s" % (hrp, rebase_5_to_32(address_hash + checksum).decode())
|
||||
|
||||
|
||||
def address2hash(address, hex = False):
|
||||
def address_to_hash(address, hex = False):
|
||||
if address[0] in ADDRESS_PREFIX_LIST:
|
||||
h = decode_base58(address)[1:-4]
|
||||
elif address[:2] in (MAINNET_SEGWIT_ADDRESS_PREFIX,
|
||||
@ -190,7 +184,7 @@ def address_type(address, num = False):
|
||||
return SCRIPT_TYPES['NON_STANDARD'] if num else 'UNKNOWN'
|
||||
return SCRIPT_TYPES[t] if num else t
|
||||
|
||||
def script2hash(s, witness = False, hex = False):
|
||||
def script_to_hash(s, witness = False, hex = False):
|
||||
if type(s) == str:
|
||||
s = unhexlify(s)
|
||||
if witness:
|
||||
@ -198,31 +192,41 @@ def script2hash(s, witness = False, hex = False):
|
||||
else:
|
||||
return hash160(s, hex)
|
||||
|
||||
def address2script(address):
|
||||
def address_to_script(address, hex = False):
|
||||
if address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX,
|
||||
MAINNET_SCRIPT_ADDRESS_PREFIX):
|
||||
return OPCODE["OP_HASH160"] + b'\x14' + address2hash(address) + OPCODE["OP_EQUAL"]
|
||||
if address[0] in (MAINNET_ADDRESS_PREFIX,
|
||||
s = [BYTE_OPCODE["OP_HASH160"],
|
||||
b'\x14',
|
||||
address_to_hash(address),
|
||||
BYTE_OPCODE["OP_EQUAL"]]
|
||||
elif address[0] in (MAINNET_ADDRESS_PREFIX,
|
||||
TESTNET_ADDRESS_PREFIX,
|
||||
TESTNET_ADDRESS_PREFIX_2):
|
||||
return OPCODE["OP_DUP"] + OPCODE["OP_HASH160"] + b'\x14' + \
|
||||
address2hash(address) + OPCODE["OP_EQUALVERIFY"] + OPCODE["OP_CHECKSIG"]
|
||||
if address[0] in (TESTNET_SEGWIT_ADDRESS_PREFIX,
|
||||
s = [BYTE_OPCODE["OP_DUP"],
|
||||
BYTE_OPCODE["OP_HASH160"],
|
||||
b'\x14',
|
||||
address_to_hash(address),
|
||||
BYTE_OPCODE["OP_EQUALVERIFY"],
|
||||
BYTE_OPCODE["OP_CHECKSIG"]]
|
||||
elif address[:2] in (TESTNET_SEGWIT_ADDRESS_PREFIX,
|
||||
MAINNET_SEGWIT_ADDRESS_PREFIX):
|
||||
h = address2hash(address)
|
||||
return OPCODE["OP_0"] + bytes([len(h)]) + h
|
||||
raise Exception("Unknown address")
|
||||
h = address_to_hash(address)
|
||||
s = [BYTE_OPCODE["OP_0"],
|
||||
bytes([len(h)]),
|
||||
h]
|
||||
else:
|
||||
assert False
|
||||
s = b''.join(s)
|
||||
return hexlify(s).decode() if hex else s
|
||||
|
||||
def script_P2SH_P2WPKH(pubkey, hash = False):
|
||||
def public_key_to_P2SH_P2WPKH_script(pubkey):
|
||||
assert len(pubkey) == 33
|
||||
if hash:
|
||||
return hash160(b'\x00\x14' + hash160(pubkey))
|
||||
return b'\x00\x14' + hash160(pubkey)
|
||||
|
||||
|
||||
def pub2address(pubkey, testnet = False,
|
||||
p2sh_p2wpkh = False,
|
||||
witness_version = 0):
|
||||
def public_key_to_address(pubkey, testnet = False,
|
||||
p2sh_p2wpkh = False,
|
||||
witness_version = 0):
|
||||
if type(pubkey) == str:
|
||||
pubkey = unhexlify(pubkey)
|
||||
if p2sh_p2wpkh:
|
||||
@ -233,18 +237,122 @@ def pub2address(pubkey, testnet = False,
|
||||
if witness_version is not None:
|
||||
assert len(pubkey) == 33
|
||||
h = hash160(pubkey)
|
||||
return hash2address(h, testnet = testnet,
|
||||
return hash_to_address(h, testnet = testnet,
|
||||
script_hash = p2sh_p2wpkh,
|
||||
witness_version = witness_version)
|
||||
|
||||
# def pub2P2SH_P2WPKH_hash(pubkey):
|
||||
# return hash160(b'\x00\x14' + hash160(pubkey))
|
||||
#
|
||||
# def pub2P2SH_P2WPKH_address(pubkey, testnet = False):
|
||||
# return hash2address(pub2P2SH_P2WPKH_hash(pubkey),
|
||||
# testnet=testnet,
|
||||
# script_hash=True,
|
||||
# witness_version=None)
|
||||
def parse_script(script, segwit=True):
|
||||
if type(script) == str:
|
||||
try:
|
||||
script = unhexlify(script)
|
||||
except:
|
||||
pass
|
||||
assert type(script) == bytes
|
||||
l = len(script)
|
||||
if segwit:
|
||||
if l == 22 and script[0] == 0:
|
||||
return {"nType": 5, "type": "P2WPKH", "reqSigs": 1, "addressHash": script[2:]}
|
||||
if l == 34 and script[0] == 0:
|
||||
return {"nType": 6, "type": "P2WSH", "reqSigs": None, "addressHash": script[2:]}
|
||||
if l == 25 and \
|
||||
script[:2] == b"\x76\xa9" and \
|
||||
script[-2:] == b"\x88\xac":
|
||||
return {"nType": 0, "type": "P2PKH", "reqSigs": 1, "addressHash": script[3:-2]}
|
||||
if l == 23 and \
|
||||
script[0] == 169 and \
|
||||
script[-1] == 135:
|
||||
return {"nType": 1, "type": "P2SH", "reqSigs": None, "addressHash": script[2:-1]}
|
||||
if l == 67 and script[-1] == 172:
|
||||
return {"nType": 2, "type": "PUBKEY", "reqSigs": 1, "addressHash": hash160(script[1:-1])}
|
||||
if l == 35 and script[-1] == 172:
|
||||
return {"nType": 2, "type": "PUBKEY", "reqSigs": 1, "addressHash": hash160(script[1:-1])}
|
||||
if script[0] == 106 and l > 1 and l <= 82:
|
||||
if script[1] == l - 2:
|
||||
return {"nType": 3, "type": "NULL_DATA", "reqSigs": 0, "data": script[2:]}
|
||||
if script[0] >= 81 and script[0] <= 96:
|
||||
if script[-1] == 174:
|
||||
if script[-2] >= 81 and script[-2] <= 96:
|
||||
if script[-2] >= script[0]:
|
||||
c, s = 0, 1
|
||||
while l - 2 - s > 0:
|
||||
if script[s] < 0x4c:
|
||||
s += script[s]
|
||||
c += 1
|
||||
else:
|
||||
c = 0
|
||||
break
|
||||
s += 1
|
||||
if c == script[-2] - 80:
|
||||
return {"nType": 4, "type": "MULTISIG", "reqSigs": script[0] - 80, "script": script}
|
||||
|
||||
s, m, n, last, req_sigs = 0, 0, 0, 0, 0
|
||||
while l - s > 0:
|
||||
if script[s] >= 81 and script[s] <= 96:
|
||||
if not n:
|
||||
n = script[s] - 80
|
||||
else:
|
||||
if m == 0:
|
||||
n, m = script[s] - 80, 0
|
||||
elif n > m:
|
||||
n, m = script[s] - 80, 0
|
||||
elif m == script[s] - 80:
|
||||
last = 0 if last else 2
|
||||
elif script[s] < 0x4c:
|
||||
s += script[s]
|
||||
m += 1
|
||||
if m > 16:
|
||||
n, m = 0, 0
|
||||
elif script[s] == OPCODE["OP_PUSHDATA1"]:
|
||||
s += 1 + script[s + 1]
|
||||
elif script[s] == OPCODE["OP_PUSHDATA2"]:
|
||||
s += 2 + struct.unpack('<H', script[s: s + 2])
|
||||
elif script[s] == OPCODE["OP_PUSHDATA4"]:
|
||||
s += 4 + struct.unpack('<L', script[s: s + 4])
|
||||
else:
|
||||
if script[s] == OPCODE["OP_CHECKSIG"]:
|
||||
req_sigs += 1
|
||||
elif script[s] == OPCODE["OP_CHECKSIGVERIFY"]:
|
||||
req_sigs += 1
|
||||
elif script[s] in (OPCODE["OP_CHECKMULTISIG"], OPCODE["OP_CHECKMULTISIGVERIFY"]):
|
||||
if last:
|
||||
req_sigs += n
|
||||
else:
|
||||
req_sigs += 20
|
||||
n, m = 0, 0
|
||||
if last:
|
||||
last -= 1
|
||||
s += 1
|
||||
return {"nType": 7, "type": "NON_STANDARD", "reqSigs": req_sigs, "script": script}
|
||||
|
||||
def decode_script(script, asm = False):
|
||||
if type(script) == str:
|
||||
try:
|
||||
script = unhexlify(script)
|
||||
except:
|
||||
pass
|
||||
assert type(script) == bytes
|
||||
l = len(script)
|
||||
s = 0
|
||||
result = []
|
||||
while l - s > 0:
|
||||
if script[s] < 0x4c and script[s]:
|
||||
if asm:
|
||||
result.append(hexlify(script[s+1:s+1 +script[s]]).decode())
|
||||
else:
|
||||
result.append('[%s]' % script[s])
|
||||
s += script[s] + 1
|
||||
continue
|
||||
elif script[s] == OPCODE["OP_PUSHDATA1"]:
|
||||
s += 1 + script[s + 1]
|
||||
elif script[s] == OPCODE["OP_PUSHDATA2"]:
|
||||
s += 2 + struct.unpack('<H', script[s: s + 2])
|
||||
elif script[s] == OPCODE["OP_PUSHDATA4"]:
|
||||
s += 4 + struct.unpack('<L', script[s: s + 4])
|
||||
result.append(RAW_OPCODE[script[s]])
|
||||
s += 1
|
||||
return ' '.join(result)
|
||||
|
||||
|
||||
|
||||
|
||||
def is_address_valid(address, testnet = False):
|
||||
@ -447,25 +555,6 @@ def is_valid_signature_encoding(sig):
|
||||
# Transaction encoding
|
||||
#
|
||||
|
||||
def bits2target(bits):
|
||||
if type(bits) == str:
|
||||
bits = unhexlify(bits)
|
||||
if type(bits) == bytes:
|
||||
return int.from_bytes(bits[1:], 'big') * (2 ** (8 * (bits[0] - 3)))
|
||||
else:
|
||||
shift = bits >> 24
|
||||
target = (bits & 0xffffff) * (1 << (8 * (shift - 3)))
|
||||
return target
|
||||
|
||||
def target2difficulty(target):
|
||||
return 0x00000000FFFF0000000000000000000000000000000000000000000000000000 / target
|
||||
|
||||
def bits2difficulty(bits):
|
||||
return target2difficulty(bits2target(bits))
|
||||
|
||||
def difficulty2target(difficulty):
|
||||
return int(0x00000000FFFF0000000000000000000000000000000000000000000000000000 / difficulty)
|
||||
|
||||
def rh2s(tthash):
|
||||
return hexlify(tthash[::-1]).decode()
|
||||
|
||||
@ -479,7 +568,9 @@ def s2rh_step4(hash_string):
|
||||
def reverse_hash(h):
|
||||
return struct.pack('>IIIIIIII', *struct.unpack('>IIIIIIII', h)[::-1])[::-1]
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
def merkleroot(tx_hash_list):
|
||||
tx_hash_list = list(tx_hash_list)
|
||||
@ -529,73 +620,143 @@ def merkleroot_from_branches(merkle_branches, coinbase_hash_bin):
|
||||
h = unhexlify(h)
|
||||
merkle_root = double_sha256(merkle_root + h)
|
||||
return merkle_root
|
||||
|
||||
def bits_to_target(bits):
|
||||
if type(bits) == str:
|
||||
bits = unhexlify(bits)
|
||||
if type(bits) == bytes:
|
||||
return int.from_bytes(bits[1:], 'big') * (2 ** (8 * (bits[0] - 3)))
|
||||
else:
|
||||
shift = bits >> 24
|
||||
target = (bits & 0xffffff) * (1 << (8 * (shift - 3)))
|
||||
return target
|
||||
|
||||
def target_to_difficulty(target):
|
||||
return 0x00000000FFFF0000000000000000000000000000000000000000000000000000 / target
|
||||
|
||||
def bits_to_difficulty(bits):
|
||||
return target_to_difficulty(bits_to_target(bits))
|
||||
|
||||
def difficulty_to_target(difficulty):
|
||||
return int(0x00000000FFFF0000000000000000000000000000000000000000000000000000 / difficulty)
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
def bytes_needed(n):
|
||||
if n == 0:
|
||||
return 1
|
||||
return math.ceil(n.bit_length()/8)
|
||||
|
||||
def var_int(data):
|
||||
e, s = 1, 0
|
||||
if data[:1] == b'\xfd':
|
||||
s, e = 1, 3
|
||||
elif data[:1] == b'\xfe':
|
||||
s = 1
|
||||
e = 5
|
||||
elif data[:1] == b'\xff':
|
||||
s = 1
|
||||
e = 9
|
||||
i = int.from_bytes(data[s:e], byteorder='little', signed=False)
|
||||
return (i, e)
|
||||
def int_to_bytes(i, byteorder='big'):
|
||||
return i.to_bytes(bytes_needed(i), byteorder=byteorder, signed=False)
|
||||
|
||||
def bytes_to_int(i, byteorder='big'):
|
||||
return int.from_bytes(i, byteorder=byteorder, signed=False)
|
||||
|
||||
|
||||
def from_var_int(data):
|
||||
# retrun
|
||||
e = 1
|
||||
s = 0
|
||||
if data[:1] == b'\xfd':
|
||||
s = 1
|
||||
e = 3
|
||||
elif data[:1] == b'\xfe':
|
||||
s = 1
|
||||
e = 5
|
||||
elif data[:1] == b'\xff':
|
||||
s = 1
|
||||
e = 9
|
||||
i = int.from_bytes(data[s:e], byteorder='little', signed=False)
|
||||
return i
|
||||
# variable integer
|
||||
|
||||
|
||||
def var_int_len(byte):
|
||||
e = 1
|
||||
if byte == 253:
|
||||
e = 3
|
||||
elif byte == 254:
|
||||
e = 5
|
||||
elif byte == 255:
|
||||
e = 9
|
||||
return e
|
||||
|
||||
|
||||
def to_var_int(i):
|
||||
if i < 253:
|
||||
return i.to_bytes(1, byteorder='little')
|
||||
def int_to_var_int(i):
|
||||
if i < 0xfd:
|
||||
return struct.pack('<B', i)
|
||||
if i <= 0xffff:
|
||||
return b'\xfd' + i.to_bytes(2, byteorder='little')
|
||||
return b'\xfd' + struct.pack('<H', i)
|
||||
if i <= 0xffffffff:
|
||||
return b'\xfe' + i.to_bytes(4, byteorder='little')
|
||||
return b'\xff' + i.to_bytes(8, byteorder='little')
|
||||
return b'\xfe' + struct.pack('<L', i)
|
||||
return b'\xff' + struct.pack('<Q', i)
|
||||
|
||||
def var_int_to_int(data):
|
||||
if data[0] == 0xfd:
|
||||
return struct.unpack('<H', data[1:3])[0]
|
||||
elif data[0] == 0xfe:
|
||||
return struct.unpack('<L', data[1:5])[0]
|
||||
elif data[0] == 0xff:
|
||||
return struct.unpack('<Q', data[1:9])[0]
|
||||
return data[0]
|
||||
|
||||
def var_int_len(n):
|
||||
if n <= 0xfc:
|
||||
return 1
|
||||
if n <= 0xffff:
|
||||
return 3
|
||||
elif n <= 0xffffffff:
|
||||
return 5
|
||||
return 9
|
||||
|
||||
def get_var_int_len(byte):
|
||||
if byte[0] == 253:
|
||||
return 3
|
||||
elif byte[0] == 254:
|
||||
return 5
|
||||
elif byte[0] == 255:
|
||||
return 9
|
||||
return 1
|
||||
|
||||
def read_var_int(stream):
|
||||
l = stream.read(1)
|
||||
bytes_length = var_int_len(l[0])
|
||||
bytes_length = get_var_int_len(l)
|
||||
return l + stream.read(bytes_length - 1)
|
||||
|
||||
|
||||
def read_var_list(stream, data_type):
|
||||
count = from_var_int(read_var_int(stream))
|
||||
count = var_int_to_int(read_var_int(stream))
|
||||
return [data_type.deserialize(stream) for i in range(count)]
|
||||
|
||||
# compressed integer
|
||||
|
||||
def int_to_c_int(n, base_bytes=1):
|
||||
if n == 0:
|
||||
return b'\x00'
|
||||
else:
|
||||
l = n.bit_length() + 1
|
||||
min_bits = base_bytes * 8 - 1
|
||||
if l <= min_bits + 1:
|
||||
return n.to_bytes(base_bytes, byteorder="big")
|
||||
prefix = 0
|
||||
payload_bytes = math.ceil((l)/8) - base_bytes
|
||||
extra_bytes = int(math.ceil((l+payload_bytes)/8) - base_bytes)
|
||||
for i in range(extra_bytes):
|
||||
prefix += 2 ** i
|
||||
if l < base_bytes * 8:
|
||||
l = base_bytes * 8
|
||||
prefix = prefix << l
|
||||
if prefix.bit_length() % 8:
|
||||
prefix = prefix << 8 - prefix.bit_length() % 8
|
||||
n ^= prefix
|
||||
return n.to_bytes(math.ceil(n.bit_length()/8), byteorder="big")
|
||||
|
||||
def c_int_to_int(b, base_bytes=1):
|
||||
byte_length = 0
|
||||
f = 0
|
||||
while True:
|
||||
v = b[f]
|
||||
if v == 0xff:
|
||||
byte_length += 8
|
||||
f += 1
|
||||
continue
|
||||
while v & 0b10000000:
|
||||
byte_length += 1
|
||||
v = v << 1
|
||||
break
|
||||
n = int.from_bytes(b[:byte_length+base_bytes], byteorder="big")
|
||||
if byte_length:
|
||||
return n & ((1 << (byte_length+base_bytes) * 8 - byte_length) - 1)
|
||||
return n
|
||||
|
||||
def c_int_len(n, base_bytes=1):
|
||||
if n == 0:
|
||||
return 1
|
||||
l = n.bit_length() + 1
|
||||
min_bits = base_bytes * 8 - 1
|
||||
if l <= min_bits + 1:
|
||||
return 1
|
||||
payload_bytes = math.ceil((l)/8) - base_bytes
|
||||
return int(math.ceil((l+payload_bytes)/8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -700,3 +861,13 @@ def i2b(i): return bn2vch(i)
|
||||
|
||||
def b2i(b): return vch2bn(b)
|
||||
|
||||
def get_stream(stream):
|
||||
if type(stream) != io.BytesIO:
|
||||
if type(stream) == str:
|
||||
stream = unhexlify(stream)
|
||||
if type(stream) == bytes:
|
||||
stream = io.BytesIO(stream)
|
||||
else:
|
||||
raise TypeError
|
||||
return stream
|
||||
|
||||
|
||||
225
pybtc/transaction.py
Normal file
225
pybtc/transaction.py
Normal file
@ -0,0 +1,225 @@
|
||||
|
||||
from struct import unpack
|
||||
import json
|
||||
from .tools import *
|
||||
from binascii import hexlify, unhexlify
|
||||
|
||||
|
||||
class Transaction(dict):
|
||||
def __init__(self, raw_tx = None):
|
||||
self["txId"] = None
|
||||
self["hash"] = None
|
||||
self["version"] = None
|
||||
self["size"] = 0
|
||||
self["vSize"] = 0
|
||||
self["bSize"] = 0
|
||||
self["lockTime"] = None
|
||||
self["vIn"] = dict()
|
||||
self["vOut"] = dict()
|
||||
self["rawTx"] = None
|
||||
self["blockHash"] = None
|
||||
self["confirmations"] = None
|
||||
self["time"] = None
|
||||
self["blockTime"] = None
|
||||
self["blockIndex"] = None
|
||||
self["coinbase"] = None
|
||||
self["fee"] = None
|
||||
self["data"] = None
|
||||
self["amount"] = 0
|
||||
if raw_tx is None:
|
||||
return
|
||||
stream = self.get_stream(raw_tx)
|
||||
start = stream.tell()
|
||||
(self["version"],) = unpack('<L', stream.read(4))
|
||||
n = read_var_int(stream)
|
||||
sw = 0
|
||||
sw_len = 0
|
||||
if n == b'\x00':
|
||||
sw = 1
|
||||
self["flag"] = stream.read(1)
|
||||
n = read_var_int(stream)
|
||||
ic = var_int_to_int(n)
|
||||
for k in range(ic):
|
||||
self["vIn"][k] = dict()
|
||||
self["vIn"][k]["txId"] = stream.read(32)
|
||||
(self["vIn"][k]["vOut"],) = unpack('<L', stream.read(4))
|
||||
n = var_int_to_int(read_var_int(stream))
|
||||
self["vIn"][k]["scriptSig"] = stream.read(n)
|
||||
(self["vIn"][k]["sequence"],) = unpack('<L', stream.read(4))
|
||||
for k in range(var_int_to_int(read_var_int(stream))):
|
||||
self["vOut"][k] = dict()
|
||||
(self["vOut"][k]["value"],) = unpack('<Q', stream.read(8))
|
||||
self["amount"] += self["vOut"][k]["value"]
|
||||
self["vOut"][k]["scriptPubKey"] = stream.read(var_int_to_int(read_var_int(stream)))
|
||||
s = parse_script(self["vOut"][k]["scriptPubKey"], sw)
|
||||
self["vOut"][k]["nType"] = s["nType"]
|
||||
self["vOut"][k]["type"] = s["type"]
|
||||
if self["data"] is None:
|
||||
if s["nType"] == 3:
|
||||
self["data"] = s["data"]
|
||||
if s["nType"] not in (3,4,7):
|
||||
self["vOut"][k]["addressHash"] = s["addressHash"]
|
||||
self["vOut"][k]["reqSigs"] = s["reqSigs"]
|
||||
if sw:
|
||||
sw = stream.tell() - start
|
||||
for k in range(ic):
|
||||
self["vIn"][k]["txInWitness"] = [stream.read(var_int_to_int(read_var_int(stream))) \
|
||||
for c in range(var_int_to_int(read_var_int(stream)))]
|
||||
sw_len = stream.tell() - sw + 2
|
||||
(self["lockTime"],) = unpack('<L', stream.read(4))
|
||||
end = stream.tell()
|
||||
stream.seek(start)
|
||||
b = stream.read(end - start)
|
||||
self["rawTx"] = b
|
||||
self["size"] = end - start
|
||||
self["bSize"] = end - start - sw_len
|
||||
self["weight"] = self["bSize"] * 3 + self["size"]
|
||||
self["vSize"] = math.ceil(self["weight"] / 4)
|
||||
if ic == 1 and \
|
||||
self["vIn"][0]["txId"] == b'\x00' * 32 and \
|
||||
self["vIn"][0]["vOut"] == 0xffffffff:
|
||||
self["coinbase"] = True
|
||||
if sw:
|
||||
self["segwit"] = True
|
||||
self["hash"] = double_sha256(b)
|
||||
self["txId"] = double_sha256(b[:4] + b[6:sw] + b[-4:])
|
||||
else:
|
||||
self["txId"] = double_sha256(b)
|
||||
self["hash"] = self["txId"]
|
||||
|
||||
def decode(self, testnet = False):
|
||||
if type(self["txId"]) == bytes:
|
||||
self["txId"] = rh2s(self["txId"])
|
||||
if "flag" in self:
|
||||
if type(self["flag"]) == bytes:
|
||||
self["flag"] = rh2s(self["flag"])
|
||||
if type(self["hash"]) == bytes:
|
||||
self["hash"] = rh2s(self["hash"])
|
||||
if type(self["rawTx"]) == bytes:
|
||||
self["rawTx"] = hexlify(self["rawTx"]).decode()
|
||||
for i in self["vIn"]:
|
||||
if type(self["vIn"][i]["txId"]) == bytes:
|
||||
self["vIn"][i]["txId"] = rh2s(self["vIn"][i]["txId"])
|
||||
if type(self["vIn"][i]["scriptSig"]) == bytes:
|
||||
self["vIn"][i]["scriptSig"] = hexlify(self["vIn"][i]["scriptSig"]).decode()
|
||||
try:
|
||||
t = list()
|
||||
for w in self["vIn"][i]["txInWitness"]:
|
||||
if type(w) == bytes:
|
||||
w = hexlify(w).decode()
|
||||
t.append(w)
|
||||
self["vIn"][i]["txInWitness"] = t
|
||||
self["vIn"][i]["txInWitnessAsm"] = [decode_script(ws, 1) for ws in self["vIn"][i]["txInWitness"]]
|
||||
self["vIn"][i]["txInWitnessOpcodes"] = [decode_script(ws) for ws in self["vIn"][i]["txInWitness"]]
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
if type(self["vIn"][i]["addressHash"]) == bytes:
|
||||
self["vIn"][i]["addressHash"] = hexlify(self["vIn"][i]["addressHash"]).decode()
|
||||
sh = True if self["vIn"][i]["nType"] in (1, 5) else False
|
||||
witness_version = None if self["vIn"][i]["nType"] < 5 else 0
|
||||
self["vIn"][i]["address"] = hash_to_address(self["vIn"][i]["addressHash"],
|
||||
testnet,
|
||||
sh,
|
||||
witness_version)
|
||||
except:
|
||||
pass
|
||||
if "scriptPubKey" in self["vIn"][i]:
|
||||
if type(self["vIn"][i]["scriptPubKey"]) == bytes:
|
||||
self["vIn"][i]["scriptPubKey"] = hexlify(self["vIn"][i]["scriptPubKey"]).decode()
|
||||
self["vIn"][i]["scriptPubKeyOpcodes"] = decode_script(self["vIn"][i]["scriptPubKey"])
|
||||
self["vIn"][i]["scriptPubKeyAsm"] = decode_script(self["vIn"][i]["scriptPubKey"], 1)
|
||||
if "redeemScript" in self["vIn"][i]:
|
||||
if type(self["vIn"][i]["redeemScript"]) == bytes:
|
||||
self["vIn"][i]["redeemScript"] = hexlify(self["vIn"][i]["redeemScript"]).decode()
|
||||
self["vIn"][i]["redeemScriptOpcodes"] = decode_script(self["vIn"][i]["redeemScript"])
|
||||
self["vIn"][i]["redeemScriptAsm"] = decode_script(self["vIn"][i]["redeemScript"], 1)
|
||||
if not self["coinbase"]:
|
||||
if type(self["vIn"][i]["scriptSig"]) == bytes:
|
||||
self["vIn"][i]["scriptSig"] = hexlify(self["vIn"][i]["scriptSig"]).decode()
|
||||
self["vIn"][i]["scriptSigOpcodes"] = decode_script(self["vIn"][i]["scriptSig"])
|
||||
self["vIn"][i]["scriptSigAsm"] = decode_script(self["vIn"][i]["scriptSig"], 1)
|
||||
|
||||
|
||||
|
||||
|
||||
for i in self["vOut"]:
|
||||
if type(self["vOut"][i]["scriptPubKey"]) == bytes:
|
||||
self["vOut"][i]["scriptPubKey"] = hexlify(self["vOut"][i]["scriptPubKey"]).decode()
|
||||
try:
|
||||
if type(self["vOut"][i]["addressHash"]) == bytes:
|
||||
self["vOut"][i]["addressHash"] = hexlify(self["vOut"][i]["addressHash"]).decode()
|
||||
sh = True if self["vOut"][i]["nType"] in (1, 5) else False
|
||||
witness_version = None if self["vOut"][i]["nType"] < 5 else 0
|
||||
self["vOut"][i]["address"] = hash_to_address(self["vOut"][i]["addressHash"],
|
||||
testnet,
|
||||
sh,
|
||||
witness_version)
|
||||
except:
|
||||
pass
|
||||
self["vOut"][i]["scriptPubKeyOpcodes"] = decode_script(self["vOut"][i]["scriptPubKey"])
|
||||
self["vOut"][i]["scriptPubKeyAsm"] = decode_script(self["vOut"][i]["scriptPubKey"], 1)
|
||||
if "data" in self:
|
||||
if type(self["data"]) == bytes:
|
||||
self["data"]= hexlify(self["data"]).decode()
|
||||
return self
|
||||
|
||||
def get_stream(self, stream):
|
||||
if type(stream) != io.BytesIO:
|
||||
if type(stream) == str:
|
||||
stream = unhexlify(stream)
|
||||
if type(stream) == bytes:
|
||||
stream = io.BytesIO(stream)
|
||||
else:
|
||||
raise TypeError
|
||||
return stream
|
||||
|
||||
def serialize(self, segwit = True, hex = False):
|
||||
chunks = []
|
||||
chunks.append(struct.pack('<L', self["version"]))
|
||||
if segwit and "segwit" in self:
|
||||
chunks.append(b"\x00\x01")
|
||||
chunks.append(int_to_var_int(len(self["vIn"])))
|
||||
for i in self["vIn"]:
|
||||
if type(self["vIn"][i]['txId']) == bytes:
|
||||
chunks.append(self["vIn"][i]['txId'])
|
||||
else:
|
||||
chunks.append(s2rh(self["vIn"][i]['txId']))
|
||||
chunks.append(struct.pack('<L', self["vIn"][i]['vOut']))
|
||||
if type(self["vIn"][i]['scriptSig']) == bytes:
|
||||
chunks.append(int_to_var_int(len(self["vIn"][i]['scriptSig'])))
|
||||
chunks.append(self["vIn"][i]['scriptSig'])
|
||||
else:
|
||||
chunks.append(int_to_var_int(int(len(self["vIn"][i]['scriptSig'])/ 2)) )
|
||||
chunks.append(unhexlify(self["vIn"][i]['scriptSig']))
|
||||
chunks.append(struct.pack('<L', self["vIn"][i]['sequence']))
|
||||
chunks.append(int_to_var_int(len(self["vOut"])))
|
||||
for i in self["vOut"]:
|
||||
chunks.append(struct.pack('<Q', self["vOut"][i]['value']))
|
||||
if type(self["vOut"][i]['scriptPubKey']) == bytes:
|
||||
chunks.append(int_to_var_int(len(self["vOut"][i]['scriptPubKey'])))
|
||||
chunks.append(self["vOut"][i]['scriptPubKey'])
|
||||
else:
|
||||
chunks.append(int_to_var_int(int(len(self["vOut"][i]['scriptPubKey'])/ 2)) )
|
||||
chunks.append(unhexlify(self["vOut"][i]['scriptPubKey']))
|
||||
if segwit and "segwit" in self:
|
||||
for i in self["vIn"]:
|
||||
chunks.append(int_to_var_int(len(self["vIn"][i]['txInWitness'])))
|
||||
for w in self["vIn"][i]['txInWitness']:
|
||||
if type(w) == bytes:
|
||||
chunks.append(int_to_var_int(len(w)))
|
||||
chunks.append(w)
|
||||
else:
|
||||
chunks.append(int_to_var_int(int(len(w)/2)))
|
||||
chunks.append(unhexlify(w))
|
||||
chunks.append(struct.pack('<L', self['lockTime']))
|
||||
tx = b''.join(chunks)
|
||||
return tx if not hex else hexlify(tx).decode()
|
||||
|
||||
def json(self):
|
||||
try:
|
||||
return json.dumps(self)
|
||||
except:
|
||||
pass
|
||||
print(self)
|
||||
return json.dumps(self.decode())
|
||||
@ -1,8 +1,12 @@
|
||||
from .script_deserialize import *
|
||||
from .hash_functions import *
|
||||
from .create_transaction import *
|
||||
from .integer import *
|
||||
from .address_functions import *
|
||||
from .transaction_deserialize import *
|
||||
from .sighash import *
|
||||
from .address_class import *
|
||||
from .ecdsa import *
|
||||
from .block import *
|
||||
from .transaction_deserialize import *
|
||||
|
||||
|
||||
# from .script_deserialize import *
|
||||
# from .create_transaction import *
|
||||
# from .sighash import *
|
||||
# from .block import *
|
||||
59
tests/test/address_class.py
Normal file
59
tests/test/address_class.py
Normal file
@ -0,0 +1,59 @@
|
||||
import unittest
|
||||
import os, sys
|
||||
parentPath = os.path.abspath("..")
|
||||
if parentPath not in sys.path:
|
||||
sys.path.insert(0, parentPath)
|
||||
|
||||
|
||||
from pybtc import address
|
||||
from pybtc import OPCODE
|
||||
from binascii import unhexlify
|
||||
|
||||
|
||||
class AddressClassTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
print("\nTesting address class:\n")
|
||||
|
||||
|
||||
def test_is_WIF_valid(self):
|
||||
p = address.PrivateKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4")
|
||||
pub = address.PublicKey(p)
|
||||
a = address.Address(p)
|
||||
self.assertEqual(a.address, 'bc1qxsms4rt5axt9674du2az7vq3pvephu3k5jyky8')
|
||||
a = address.Address(p, address_type = "P2PKH")
|
||||
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
||||
a = address.Address(p, address_type = "PUBKEY")
|
||||
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
||||
a = address.Address(p, address_type = "P2SH_P2WPKH")
|
||||
self.assertEqual(a.address, '37WJdFAoHDbxUQioDgtvPZuyJPyrrNQ7aL')
|
||||
self.assertEqual(a.redeem_script_hex, '001434370a8d74e9965d7aade2ba2f30110b321bf236')
|
||||
self.assertEqual(a.public_key.hex(), '02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
|
||||
|
||||
# compressed public key
|
||||
p = address.PrivateKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76", compressed=False)
|
||||
pub = address.PublicKey(p)
|
||||
a = address.Address(p, address_type="P2PKH")
|
||||
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
||||
a = address.Address(p, address_type="PUBKEY")
|
||||
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
||||
|
||||
# from pubkey
|
||||
p = address.PublicKey('02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
|
||||
a = address.Address(p)
|
||||
self.assertEqual(a.address, 'bc1qxsms4rt5axt9674du2az7vq3pvephu3k5jyky8')
|
||||
a = address.Address(p, address_type="P2PKH")
|
||||
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
||||
a = address.Address(p, address_type="PUBKEY")
|
||||
self.assertEqual(a.address, '15m65JmFohJiioQbzMWhqFeCS3ZL1KVaNh')
|
||||
a = address.Address(p, address_type="P2SH_P2WPKH")
|
||||
self.assertEqual(a.address, '37WJdFAoHDbxUQioDgtvPZuyJPyrrNQ7aL')
|
||||
self.assertEqual(a.redeem_script_hex, '001434370a8d74e9965d7aade2ba2f30110b321bf236')
|
||||
self.assertEqual(a.public_key.hex(), '02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
|
||||
|
||||
# from uncompressed pubkey
|
||||
p = address.PublicKey('04a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb43bbd96a641808e5f34eb568e804fe679de82de419e2512736ea09013a82324a6')
|
||||
a = address.Address(p, address_type="P2PKH")
|
||||
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
||||
a = address.Address(p, address_type="PUBKEY")
|
||||
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
|
||||
@ -1,7 +1,12 @@
|
||||
import unittest
|
||||
import os, sys
|
||||
parentPath = os.path.abspath("..")
|
||||
if parentPath not in sys.path:
|
||||
sys.path.insert(0, parentPath)
|
||||
|
||||
from pybtc import tools
|
||||
from pybtc import OPCODE
|
||||
from binascii import unhexlify
|
||||
from pybtc import BYTE_OPCODE, HEX_OPCODE
|
||||
from binascii import unhexlify, hexlify
|
||||
|
||||
|
||||
class AddressFunctionsTests(unittest.TestCase):
|
||||
@ -9,16 +14,16 @@ class AddressFunctionsTests(unittest.TestCase):
|
||||
def setUpClass(cls):
|
||||
print("\nTesting address functions:\n")
|
||||
|
||||
def test_priv2WIF(self):
|
||||
def test_private_key_to_WIF(self):
|
||||
p = "ceda1ae4286015d45ec5147fe3f63e9377ccd6d4e98bcf0847df9937da1944a4"
|
||||
pcm = "L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX"
|
||||
pum = "5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf"
|
||||
put = "93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L"
|
||||
pct = "cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6"
|
||||
self.assertEqual(tools.priv2WIF(p, compressed=1, testnet=0),pcm)
|
||||
self.assertEqual(tools.priv2WIF(p, compressed=0, testnet=0),pum)
|
||||
self.assertEqual(tools.priv2WIF(p, compressed=1, testnet=1),pct)
|
||||
self.assertEqual(tools.priv2WIF(p, compressed=0, testnet=1),put)
|
||||
self.assertEqual(tools.private_key_to_WIF(p, compressed=1, testnet=0), pcm)
|
||||
self.assertEqual(tools.private_key_to_WIF(p, compressed=0, testnet=0), pum)
|
||||
self.assertEqual(tools.private_key_to_WIF(p, compressed=1, testnet=1), pct)
|
||||
self.assertEqual(tools.private_key_to_WIF(p, compressed=0, testnet=1), put)
|
||||
|
||||
def test_is_WIF_valid(self):
|
||||
self.assertEqual(tools.is_WIF_valid("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX"),1)
|
||||
@ -28,64 +33,76 @@ class AddressFunctionsTests(unittest.TestCase):
|
||||
self.assertEqual(tools.is_WIF_valid("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6"),1)
|
||||
self.assertEqual(tools.is_WIF_valid("cUWo47XLYiyByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6"),0)
|
||||
|
||||
def test_WIF2priv(self):
|
||||
def test_WIF_to_private_key(self):
|
||||
p = "ceda1ae4286015d45ec5147fe3f63e9377ccd6d4e98bcf0847df9937da1944a4"
|
||||
self.assertEqual(tools.WIF2priv("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX",
|
||||
hex=1),p)
|
||||
self.assertEqual(tools.WIF2priv("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX",
|
||||
hex=0),unhexlify(p))
|
||||
self.assertEqual(tools.WIF2priv("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf",
|
||||
hex=1),p)
|
||||
self.assertEqual(tools.WIF2priv("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L",
|
||||
hex=1),p)
|
||||
self.assertEqual(tools.WIF2priv("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6",
|
||||
hex=1),p)
|
||||
self.assertEqual(tools.WIF_to_private_key("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX",
|
||||
hex=1),p)
|
||||
self.assertEqual(tools.WIF_to_private_key("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX",
|
||||
hex=0),unhexlify(p))
|
||||
self.assertEqual(tools.WIF_to_private_key("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf",
|
||||
hex=1),p)
|
||||
self.assertEqual(tools.WIF_to_private_key("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L",
|
||||
hex=1),p)
|
||||
self.assertEqual(tools.WIF_to_private_key("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6",
|
||||
hex=1),p)
|
||||
|
||||
def test_priv2pub(self):
|
||||
def test_create_private_key(self):
|
||||
p = tools.create_private_key()
|
||||
pw = tools.private_key_to_WIF(p)
|
||||
self.assertEqual(tools.is_WIF_valid(pw), True)
|
||||
|
||||
|
||||
|
||||
def test_private_to_public_key(self):
|
||||
p = "ceda1ae4286015d45ec5147fe3f63e9377ccd6d4e98bcf0847df9937da1944a4"
|
||||
pu = "04b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4c8cbe28702911260f2a1da099a338bed4ee98f66bb8dba8031a76ab537ff6663"
|
||||
pk = "03b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4"
|
||||
self.assertEqual(tools.priv2pub(p, hex=1),pk)
|
||||
self.assertEqual(tools.priv2pub(p, hex=0),unhexlify(pk))
|
||||
self.assertEqual(tools.priv2pub(p, compressed=0, hex=1),pu)
|
||||
self.assertEqual(tools.priv2pub("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX", hex=1),pk)
|
||||
self.assertEqual(tools.priv2pub("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf", hex=1),pu)
|
||||
self.assertEqual(tools.priv2pub("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L", hex=1),pu)
|
||||
self.assertEqual(tools.priv2pub("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6", hex=1),pk)
|
||||
self.assertEqual(tools.private_to_public_key(p, hex=1), pk)
|
||||
self.assertEqual(tools.private_to_public_key(p, hex=0), unhexlify(pk))
|
||||
self.assertEqual(tools.private_to_public_key(p, compressed=0, hex=1), pu)
|
||||
self.assertEqual(tools.private_to_public_key("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX", hex=1), pk)
|
||||
self.assertEqual(tools.private_to_public_key("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf", hex=1), pu)
|
||||
self.assertEqual(tools.private_to_public_key("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L", hex=1), pu)
|
||||
self.assertEqual(tools.private_to_public_key("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6", hex=1), pk)
|
||||
|
||||
def test_hash2address(self):
|
||||
def test_hash_to_address(self):
|
||||
pc = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
|
||||
h = tools.hash160(pc)
|
||||
s = bytes([len(unhexlify(pc))])+unhexlify(pc) + OPCODE["OP_CHECKSIG"]
|
||||
self.assertEqual(tools.hash2address(h), "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
||||
self.assertEqual(tools.hash2address(h, testnet=1), "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx")
|
||||
h = tools.script2hash(s, 1, 1)
|
||||
self.assertEqual(tools.hash2address(h), "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3")
|
||||
self.assertEqual(tools.hash2address(h, testnet=1), "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7")
|
||||
s = bytes([len(unhexlify(pc))])+unhexlify(pc) + BYTE_OPCODE["OP_CHECKSIG"]
|
||||
self.assertEqual(tools.hash_to_address(h), "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
||||
self.assertEqual(tools.hash_to_address(h, testnet=1), "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx")
|
||||
h = tools.script_to_hash(s, 1, 1)
|
||||
self.assertEqual(tools.hash_to_address(h), "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3")
|
||||
self.assertEqual(tools.hash_to_address(h, testnet=1), "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7")
|
||||
pk = "03b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4"
|
||||
h = tools.hash160(pk)
|
||||
self.assertEqual(tools.hash2address(h, witness_version=None), "1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1")
|
||||
self.assertEqual(tools.hash2address(h, witness_version=None, testnet=1), "mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c")
|
||||
self.assertEqual(tools.hash_to_address(h, witness_version=None), "1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1")
|
||||
self.assertEqual(tools.hash_to_address(h, witness_version=None, testnet=1), "mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c")
|
||||
# p2wpkh inside p2sh
|
||||
p = "L32a8Mo1LgvjrVDbzcc3NkuUfkpoLsf2Y2oEWkV4t1KpQdFzuyff"
|
||||
pk = tools.priv2pub(p)
|
||||
pk = tools.private_to_public_key(p)
|
||||
script = b'\x00\x14' + tools.hash160(pk)
|
||||
script_hash = tools.hash160(script)
|
||||
self.assertEqual(tools.hash2address(script_hash, script_hash=1, witness_version=None), "33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw")
|
||||
self.assertEqual(tools.hash2address(script_hash, script_hash=1, witness_version=None, testnet=1), "2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh")
|
||||
self.assertEqual(tools.hash_to_address(script_hash,
|
||||
script_hash=1,
|
||||
witness_version=None), "33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw")
|
||||
self.assertEqual(tools.hash_to_address(script_hash,
|
||||
script_hash=1,
|
||||
witness_version=None,
|
||||
testnet=1), "2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh")
|
||||
|
||||
def test_address2hash(self):
|
||||
def test_address_to_hash(self):
|
||||
h = "751e76e8199196d454941c45d1b3a323f1433bd6"
|
||||
self.assertEqual(tools.address2hash("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1), h)
|
||||
self.assertEqual(tools.address2hash("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx", 1), h)
|
||||
self.assertEqual(tools.address_to_hash("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1), h)
|
||||
self.assertEqual(tools.address_to_hash("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx", 1), h)
|
||||
h = "1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"
|
||||
self.assertEqual(tools.address2hash("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", 1), h)
|
||||
self.assertEqual(tools.address_to_hash("bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", 1), h)
|
||||
h = "a307d67484911deee457779b17505cedd20e1fe9"
|
||||
self.assertEqual(tools.address2hash("1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1", 1), h)
|
||||
self.assertEqual(tools.address2hash("mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c", 1), h)
|
||||
self.assertEqual(tools.address_to_hash("1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1", 1), h)
|
||||
self.assertEqual(tools.address_to_hash("mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c", 1), h)
|
||||
h = "14c14c8d26acbea970757b78e6429ad05a6ac6bb"
|
||||
self.assertEqual(tools.address2hash("33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw", 1), h)
|
||||
self.assertEqual(tools.address2hash("2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh", 1), h)
|
||||
self.assertEqual(tools.address_to_hash("33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw", 1), h)
|
||||
self.assertEqual(tools.address_to_hash("2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh", 1), h)
|
||||
|
||||
def test_address_type(self):
|
||||
self.assertEqual(tools.address_type("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"), 'P2WPKH')
|
||||
@ -97,16 +114,20 @@ class AddressFunctionsTests(unittest.TestCase):
|
||||
self.assertEqual(tools.address_type("33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw"), 'P2SH')
|
||||
self.assertEqual(tools.address_type("2Mu8y4mm4oF88yppDbUAAEwyBEPezrx7CLh"), 'P2SH')
|
||||
|
||||
def test_pub2address(self):
|
||||
def test_public_key_to_address(self):
|
||||
pc = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
|
||||
self.assertEqual(tools.pub2address(pc), "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
||||
self.assertEqual(tools.pub2address(pc, testnet=1), "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx")
|
||||
self.assertEqual(tools.public_key_to_address(pc), "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
||||
self.assertEqual(tools.public_key_to_address(pc, testnet=1), "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx")
|
||||
pc = "03b635dbdc16dbdf4bb9cf5b55e7d03e514fb04dcef34208155c7d3ec88e9045f4"
|
||||
self.assertEqual(tools.pub2address(pc, witness_version=None, testnet=0), "1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1")
|
||||
self.assertEqual(tools.pub2address(pc, witness_version=None, testnet=1), "mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c")
|
||||
self.assertEqual(tools.public_key_to_address(pc,
|
||||
witness_version=None,
|
||||
testnet=0), "1Fs2Xqrk4P2XADaJeZWykaGXJ4HEb6RyT1")
|
||||
self.assertEqual(tools.public_key_to_address(pc, witness_version=None,
|
||||
testnet=1), "mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c")
|
||||
p = "L32a8Mo1LgvjrVDbzcc3NkuUfkpoLsf2Y2oEWkV4t1KpQdFzuyff"
|
||||
pk = tools.priv2pub(p)
|
||||
self.assertEqual(tools.pub2address(pk, p2sh_p2wpkh=1,witness_version=None), "33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw")
|
||||
pk = tools.private_to_public_key(p)
|
||||
self.assertEqual(tools.public_key_to_address(pk, p2sh_p2wpkh=1,
|
||||
witness_version=None), "33am12q3Bncnn3BfvLYHczyv23Sq2Wbwjw")
|
||||
|
||||
def test_is_address_valid(self):
|
||||
self.assertEqual(tools.is_address_valid("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"), 1)
|
||||
@ -127,3 +148,381 @@ class AddressFunctionsTests(unittest.TestCase):
|
||||
self.assertEqual(tools.is_address_valid("mvNyptwisQTkwL3vN8VMaVUrA3swVCX83c", 1), 0)
|
||||
self.assertEqual(tools.is_address_valid("33am12q3Bncmn3BfvLYHczyv23Sq2Wbwjw"), 0)
|
||||
self.assertEqual(tools.is_address_valid("2Mu8y4mm4oF78yppDbUAAEwyBEPezrx7CLh", 1), 0)
|
||||
|
||||
def test_address_to_script(self):
|
||||
self.assertEqual(tools.address_to_script("17rPqUf4Hqu6Lvpgfsavt1CzRy2GL19GD3", 1),
|
||||
"76a9144b2832feeda5692c96c0594a6314136a998f515788ac")
|
||||
self.assertEqual(tools.address_to_script("33RYUa9jT541UNPsKdV7V1DmwMiQHpVfD3", 1),
|
||||
"a914130319921ecbcfa33fec2a8503c4ae1c86e4419387")
|
||||
self.assertEqual(tools.address_to_script("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1),
|
||||
"0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
||||
self.assertEqual(tools.address_to_script("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", 1),
|
||||
"0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
||||
|
||||
def test_parse_script(self):
|
||||
|
||||
k = tools.parse_script("76a9144b2832feeda5692c96c0594a6314136a998f515788ac")
|
||||
address = tools.hash_to_address(k["addressHash"], witness_version = None)
|
||||
self.assertEqual(address, "17rPqUf4Hqu6Lvpgfsavt1CzRy2GL19GD3")
|
||||
self.assertEqual(k["type"],"P2PKH")
|
||||
self.assertEqual(k["nType"],0)
|
||||
self.assertEqual(k["reqSigs"],1)
|
||||
self.assertEqual(tools.address_to_script(address, 1),
|
||||
"76a9144b2832feeda5692c96c0594a6314136a998f515788ac")
|
||||
|
||||
k = tools.parse_script("76a914a307d67484911deee457779b17505cedd20e1fe988ac")
|
||||
address = tools.hash_to_address(k["addressHash"],testnet= True, witness_version = None)
|
||||
self.assertEqual(address,"mvNyptwisQTmwL3vN8VMaVUrA3swVCX83c")
|
||||
self.assertEqual(k["type"],"P2PKH")
|
||||
self.assertEqual(k["nType"],0)
|
||||
self.assertEqual(k["reqSigs"],1)
|
||||
self.assertEqual(tools.address_to_script(address, 1),
|
||||
"76a914a307d67484911deee457779b17505cedd20e1fe988ac")
|
||||
|
||||
k = tools.parse_script("a914b316ac9bdd0816ecdec6773d1192c0eaf52ae66487")
|
||||
address = tools.hash_to_address(k["addressHash"],script_hash = True ,witness_version = None)
|
||||
self.assertEqual(address, "3J1x3KHjgjoTjqHjrwKax2zeT8LSDkZJae")
|
||||
self.assertEqual(k["type"],"P2SH")
|
||||
self.assertEqual(k["nType"],1)
|
||||
self.assertEqual(k["reqSigs"], None)
|
||||
self.assertEqual(tools.address_to_script(address, 1),
|
||||
"a914b316ac9bdd0816ecdec6773d1192c0eaf52ae66487")
|
||||
|
||||
k = tools.parse_script("0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
||||
address = tools.hash_to_address(k["addressHash"],script_hash = False,
|
||||
witness_version = 0, testnet = False)
|
||||
self.assertEqual(address, "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
||||
self.assertEqual(k["type"],"P2WPKH")
|
||||
self.assertEqual(k["nType"],5)
|
||||
self.assertEqual(k["reqSigs"],1)
|
||||
self.assertEqual(tools.address_to_script(address, 1),
|
||||
"0014751e76e8199196d454941c45d1b3a323f1433bd6")
|
||||
|
||||
s = [HEX_OPCODE['OP_HASH160'],
|
||||
'14',
|
||||
'92c2f2da37093971ca335824edae06468e60ea20',
|
||||
HEX_OPCODE['OP_EQUAL']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
address = tools.hash_to_address(k["addressHash"],script_hash = True,
|
||||
witness_version = None, testnet = False)
|
||||
self.assertEqual(address, "3F527pX8o2pgr6FuNdNvngA2Do2wVvDoZi")
|
||||
self.assertEqual(k["type"],"P2SH")
|
||||
self.assertEqual(k["nType"],1)
|
||||
self.assertEqual(k["reqSigs"], None)
|
||||
self.assertEqual(tools.address_to_script(address, 1), h)
|
||||
|
||||
s = [HEX_OPCODE['OP_3'],
|
||||
'21',
|
||||
'021ecd2e5eb5dbd7c8e59f66e37da2ae95f7d61a07f4b2567c3bb10bbb1b2ec953',
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
sh = tools.script_to_hash(h, witness = False)
|
||||
address = tools.hash_to_address(sh,script_hash = True,
|
||||
witness_version = None, testnet = False)
|
||||
self.assertEqual(address, "3D2oetdNuZUqQHPJmcMDDHYoqkyNVsFk9r")
|
||||
self.assertEqual(k["type"],"MULTISIG")
|
||||
self.assertEqual(k["nType"],4)
|
||||
self.assertEqual(k["reqSigs"],3)
|
||||
|
||||
s = [HEX_OPCODE['OP_0'],
|
||||
'21',
|
||||
'021ecd2e5eb5dbd7c8e59f66e37da2ae95f7d61a07f4b2567c3bb10bbb1b2ec953',
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
sh = tools.script_to_hash(h, witness = False)
|
||||
self.assertEqual(k["type"],"NON_STANDARD")
|
||||
self.assertEqual(k["nType"],7)
|
||||
self.assertEqual(k["reqSigs"],20)
|
||||
|
||||
s = [HEX_OPCODE['OP_1'],
|
||||
'21',
|
||||
'021ecd2e5eb5dbd7c8e59f66e37da2ae95f7d61a07f4b2567c3bb10bbb1b2ec953',
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
self.assertEqual(k["type"],"MULTISIG")
|
||||
self.assertEqual(k["nType"],4)
|
||||
self.assertEqual(k["reqSigs"],1)
|
||||
|
||||
|
||||
|
||||
s = [HEX_OPCODE['OP_1'],
|
||||
HEX_OPCODE['OP_1'],
|
||||
'21',
|
||||
'021ecd2e5eb5dbd7c8e59f66e37da2ae95f7d61a07f4b2567c3bb10bbb1b2ec953',
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
sh = tools.script_to_hash(h, witness = False)
|
||||
self.assertEqual(k["type"],"NON_STANDARD")
|
||||
self.assertEqual(k["nType"],7)
|
||||
self.assertEqual(k["reqSigs"],1)
|
||||
|
||||
s = [HEX_OPCODE['OP_1'],
|
||||
HEX_OPCODE['OP_6'],
|
||||
'21',
|
||||
'021ecd2e5eb5dbd7c8e59f66e37da2ae95f7d61a07f4b2567c3bb10bbb1b2ec953',
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
self.assertEqual(k["type"],"NON_STANDARD")
|
||||
self.assertEqual(k["nType"],7)
|
||||
self.assertEqual(k["reqSigs"],6)
|
||||
|
||||
s = [HEX_OPCODE['OP_1'],
|
||||
HEX_OPCODE['OP_6'],
|
||||
'21',
|
||||
'021ecd2e5eb5dbd7c8e59f66e37da2ae95f7d61a07f4b2567c3bb10bbb1b2ec953',
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
self.assertEqual(k["type"],"NON_STANDARD")
|
||||
self.assertEqual(k["nType"],7)
|
||||
self.assertEqual(k["reqSigs"],20)
|
||||
|
||||
s = [HEX_OPCODE['OP_1'],
|
||||
HEX_OPCODE['OP_6'],
|
||||
'21',
|
||||
'021ecd2e5eb5dbd7c8e59f66e37da2ae95f7d61a07f4b2567c3bb10bbb1b2ec953',
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKSIG'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
self.assertEqual(k["type"],"NON_STANDARD")
|
||||
self.assertEqual(k["nType"],7)
|
||||
self.assertEqual(k["reqSigs"],21)
|
||||
|
||||
|
||||
s = [HEX_OPCODE['OP_1'],
|
||||
HEX_OPCODE['OP_6'],
|
||||
'21',
|
||||
'021ecd2e5eb5dbd7c8e59f66e37da2ae95f7d61a07f4b2567c3bb10bbb1b2ec953',
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
self.assertEqual(k["type"],"NON_STANDARD")
|
||||
self.assertEqual(k["nType"],7)
|
||||
self.assertEqual(k["reqSigs"],20)
|
||||
|
||||
s = [
|
||||
HEX_OPCODE['OP_6'],
|
||||
'21',
|
||||
'021ecd2e5eb5dbd7c8e59f66e37da2ae95f7d61a07f4b2567c3bb10bbb1b2ec953',
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
self.assertEqual(k["type"],"NON_STANDARD")
|
||||
self.assertEqual(k["nType"],7)
|
||||
self.assertEqual(k["reqSigs"],20)
|
||||
|
||||
|
||||
s = [
|
||||
HEX_OPCODE['OP_6'],
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
self.assertEqual(k["type"],"MULTISIG")
|
||||
self.assertEqual(k["nType"],4)
|
||||
self.assertEqual(k["reqSigs"],6)
|
||||
|
||||
|
||||
s = [
|
||||
HEX_OPCODE['OP_1'],
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
self.assertEqual(k["type"],"MULTISIG")
|
||||
self.assertEqual(k["nType"],4)
|
||||
self.assertEqual(k["reqSigs"],1)
|
||||
|
||||
|
||||
|
||||
s = [
|
||||
HEX_OPCODE['OP_1'],
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
'21',
|
||||
'02b63fe474a5daac88eb74fdc9ce0ec69a8f8b81d2d89ac8d518a2f54d4bcaf4a5',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
self.assertEqual(k["type"],"NON_STANDARD")
|
||||
self.assertEqual(k["nType"],7)
|
||||
self.assertEqual(k["reqSigs"],20)
|
||||
|
||||
|
||||
s = [
|
||||
HEX_OPCODE['OP_1'],
|
||||
'21',
|
||||
'023bd78b0e7606fc1205721e4403355dfc0dbe4f1b15712cbbb17b1dc323cc8c0b',
|
||||
'21',
|
||||
'02afa49972b95496b39e7adc13437239ded698d81c85e9d029debb88641733528d',
|
||||
HEX_OPCODE['OP_DUP'],
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
'21',
|
||||
'03fedb540dd71a0211170b1857a3888d9f950231ecd0fcc7a37ffe094721ca151f',
|
||||
'21',
|
||||
'02fb394aaf232e114c06b1d1ca15f97602d2377c33e6fe5a1287421b09b08a5a3e',
|
||||
HEX_OPCODE['OP_6'],
|
||||
HEX_OPCODE['OP_CHECKMULTISIG']]
|
||||
h = ''.join(s)
|
||||
s = unhexlify(h)
|
||||
k = tools.parse_script(s)
|
||||
self.assertEqual(k["type"],"NON_STANDARD")
|
||||
self.assertEqual(k["nType"],7)
|
||||
self.assertEqual(k["reqSigs"],20)
|
||||
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
import unittest
|
||||
import os, sys
|
||||
parentPath = os.path.abspath("..")
|
||||
if parentPath not in sys.path:
|
||||
sys.path.insert(0, parentPath)
|
||||
|
||||
from pybtc import blockchain
|
||||
from binascii import unhexlify
|
||||
from pybtc import rh2s
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import unittest
|
||||
import os, sys
|
||||
parentPath = os.path.abspath("..")
|
||||
if parentPath not in sys.path:
|
||||
sys.path.insert(0, parentPath)
|
||||
from pybtc import *
|
||||
from binascii import unhexlify
|
||||
from pybtc import address2hash as address2hash160
|
||||
from pybtc import address_to_hash as address2hash160
|
||||
|
||||
class CreateTransactionTests(unittest.TestCase):
|
||||
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
import unittest
|
||||
import os, sys
|
||||
parentPath = os.path.abspath("..")
|
||||
if parentPath not in sys.path:
|
||||
sys.path.insert(0, parentPath)
|
||||
from pybtc import *
|
||||
|
||||
class ECDSATests(unittest.TestCase):
|
||||
@ -13,7 +17,7 @@ class ECDSATests(unittest.TestCase):
|
||||
print("\nPrivate key to Public key ")
|
||||
k = bytearray.fromhex("eb696a065ef48a2192da5b28b694f87544b30fae8327c4510137a922f32c6dcf")
|
||||
|
||||
self.assertEqual(priv2pub(k, hex=True),
|
||||
self.assertEqual(private_to_public_key(k, hex=True),
|
||||
"03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873")
|
||||
print("Sign message")
|
||||
msg = bytearray.fromhex('64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6')
|
||||
@ -21,6 +25,6 @@ class ECDSATests(unittest.TestCase):
|
||||
"3044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb")
|
||||
print("Verify signature")
|
||||
s = '3044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb'
|
||||
self.assertEqual(verify_signature(s,priv2pub(k, hex=True), msg), True)
|
||||
self.assertEqual(verify_signature(s, private_to_public_key(k, hex=True), msg), True)
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
import unittest
|
||||
import os, sys
|
||||
parentPath = os.path.abspath("..")
|
||||
if parentPath not in sys.path:
|
||||
sys.path.insert(0, parentPath)
|
||||
from pybtc import tools
|
||||
from binascii import unhexlify, hexlify
|
||||
|
||||
|
||||
115
tests/test/integer.py
Normal file
115
tests/test/integer.py
Normal file
@ -0,0 +1,115 @@
|
||||
import unittest
|
||||
import os, sys
|
||||
parentPath = os.path.abspath("..")
|
||||
if parentPath not in sys.path:
|
||||
sys.path.insert(0, parentPath)
|
||||
from pybtc import tools
|
||||
|
||||
|
||||
|
||||
def print_bytes(b):
|
||||
for i in range(len(b)):
|
||||
print(bin(b[i])[2:].rjust(8, '0'), end = ' ')
|
||||
print("\n", end="")
|
||||
|
||||
class IntegerFunctionsTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
print("\nTesting compressed/variable int functions:\n")
|
||||
|
||||
def test_compressed_integer(self):
|
||||
# print()
|
||||
for i in range(126, 130):
|
||||
# print(i, "[", len(tools.int_to_c_int(i)), "]", end=" : " )
|
||||
# print_bytes(tools.int_to_c_int(i))
|
||||
# print(bin(tools.c_int_to_int((tools.int_to_c_int(i)))))
|
||||
self.assertEqual(tools.c_int_to_int((tools.int_to_c_int(i))), i)
|
||||
self.assertEqual(tools.c_int_len(i), len(tools.int_to_c_int(i)))
|
||||
self.assertEqual(len(tools.int_to_c_int(i)), 2)
|
||||
for i in range(16382, 16386):
|
||||
# print(i, "[", len(tools.int_to_c_int(i)), "]", end=" : " )
|
||||
# print_bytes(tools.int_to_c_int(i))
|
||||
# print(bin(tools.c_int_to_int((tools.int_to_c_int(i)))))
|
||||
self.assertEqual(tools.c_int_to_int((tools.int_to_c_int(i))), i)
|
||||
self.assertEqual(tools.c_int_len(i), len(tools.int_to_c_int(i)))
|
||||
self.assertEqual(len(tools.int_to_c_int(i)), 3)
|
||||
for i in range(2097149, 2097154):
|
||||
# print(i, "[", len(tools.int_to_c_int(i)), "]", end=" : " )
|
||||
# print_bytes(tools.int_to_c_int(i))
|
||||
# print(bin(tools.c_int_to_int((tools.int_to_c_int(i)))))
|
||||
self.assertEqual(tools.c_int_to_int((tools.int_to_c_int(i))), i)
|
||||
self.assertEqual(tools.c_int_len(i), len(tools.int_to_c_int(i)))
|
||||
self.assertEqual(len(tools.int_to_c_int(i)), 4)
|
||||
for i in range(268435454, 268435458):
|
||||
# print(i, "[", len(tools.int_to_c_int(i)), "]", end=" : " )
|
||||
# print_bytes(tools.int_to_c_int(i))
|
||||
# print(bin(tools.c_int_to_int((tools.int_to_c_int(i)))))
|
||||
self.assertEqual(tools.c_int_to_int((tools.int_to_c_int(i))), i)
|
||||
self.assertEqual(tools.c_int_len(i), len(tools.int_to_c_int(i)))
|
||||
self.assertEqual(len(tools.int_to_c_int(i)), 5)
|
||||
for i in range(34359738366, 34359738370):
|
||||
# print(i, "[", len(tools.int_to_c_int(i)), "]", end=" : " )
|
||||
# print_bytes(tools.int_to_c_int(i))
|
||||
# print(bin(tools.c_int_to_int((tools.int_to_c_int(i)))))
|
||||
self.assertEqual(tools.c_int_to_int((tools.int_to_c_int(i))), i)
|
||||
self.assertEqual(tools.c_int_len(i), len(tools.int_to_c_int(i)))
|
||||
self.assertEqual(len(tools.int_to_c_int(i)), 6)
|
||||
for i in range(4398046511102, 4398046511106):
|
||||
# print(i, "[", len(tools.int_to_c_int(i)), "]", end=" : " )
|
||||
# print_bytes(tools.int_to_c_int(i))
|
||||
# print(bin(tools.c_int_to_int((tools.int_to_c_int(i)))))
|
||||
self.assertEqual(tools.c_int_to_int((tools.int_to_c_int(i))), i)
|
||||
self.assertEqual(tools.c_int_len(i), len(tools.int_to_c_int(i)))
|
||||
self.assertEqual(len(tools.int_to_c_int(i)), 7)
|
||||
for i in range(562949953421310, 562949953421314):
|
||||
# print(i, "[", len(tools.int_to_c_int(i)), "]", end=" : " )
|
||||
# print_bytes(tools.int_to_c_int(i))
|
||||
# print(bin(tools.c_int_to_int((tools.int_to_c_int(i)))))
|
||||
self.assertEqual(tools.c_int_to_int((tools.int_to_c_int(i))), i)
|
||||
self.assertEqual(tools.c_int_len(i), len(tools.int_to_c_int(i)))
|
||||
self.assertEqual(len(tools.int_to_c_int(i)), 8)
|
||||
for i in range(72057594037927934, 72057594037927938):
|
||||
# print(i, "[", len(tools.int_to_c_int(i)), "]", end=" : " )
|
||||
# print_bytes(tools.int_to_c_int(i))
|
||||
# print(bin(tools.c_int_to_int((tools.int_to_c_int(i)))))
|
||||
self.assertEqual(tools.c_int_to_int((tools.int_to_c_int(i))), i)
|
||||
self.assertEqual(tools.c_int_len(i), len(tools.int_to_c_int(i)))
|
||||
self.assertEqual(len(tools.int_to_c_int(i)), 9)
|
||||
i = 16250249101024000000
|
||||
self.assertEqual(tools.c_int_to_int((tools.int_to_c_int(i))), i)
|
||||
self.assertEqual(tools.c_int_len(i), len(tools.int_to_c_int(i)))
|
||||
self.assertEqual(len(tools.int_to_c_int(i)), 10)
|
||||
|
||||
i = 0
|
||||
self.assertEqual(tools.c_int_to_int((tools.int_to_c_int(i))), i)
|
||||
self.assertEqual(tools.c_int_len(i), len(tools.int_to_c_int(i)))
|
||||
self.assertEqual(len(tools.int_to_c_int(i)), 1)
|
||||
|
||||
def test_variable_integer(self):
|
||||
for i in range(0, 0xfd):
|
||||
self.assertEqual(tools.var_int_to_int((tools.int_to_var_int(i))), i)
|
||||
self.assertEqual(tools.var_int_len(i), len(tools.int_to_var_int(i)))
|
||||
self.assertEqual(tools.var_int_len(i), 1)
|
||||
for i in range(0xfd, 0xfff):
|
||||
self.assertEqual(tools.var_int_to_int((tools.int_to_var_int(i))), i)
|
||||
self.assertEqual(len(tools.int_to_var_int(i)), 3)
|
||||
self.assertEqual(tools.var_int_len(i), len(tools.int_to_var_int(i)))
|
||||
for i in range(0xfff0, 0xffff):
|
||||
self.assertEqual(tools.var_int_to_int((tools.int_to_var_int(i))), i)
|
||||
self.assertEqual(len(tools.int_to_var_int(i)), 3)
|
||||
self.assertEqual(tools.var_int_len(i), len(tools.int_to_var_int(i)))
|
||||
for i in range(0x10000, 0x10010):
|
||||
self.assertEqual(tools.var_int_to_int((tools.int_to_var_int(i))), i)
|
||||
self.assertEqual(len(tools.int_to_var_int(i)), 5)
|
||||
self.assertEqual(tools.var_int_len(i), len(tools.int_to_var_int(i)))
|
||||
for i in range(0xffffff00, 0xffffffff):
|
||||
self.assertEqual(tools.var_int_to_int((tools.int_to_var_int(i))), i)
|
||||
self.assertEqual(len(tools.int_to_var_int(i)), 5)
|
||||
self.assertEqual(tools.var_int_len(i), len(tools.int_to_var_int(i)))
|
||||
for i in range(0x100000000, 0x100001000):
|
||||
self.assertEqual(tools.var_int_to_int((tools.int_to_var_int(i))), i)
|
||||
self.assertEqual(len(tools.int_to_var_int(i)), 9)
|
||||
self.assertEqual(tools.var_int_len(i), len(tools.int_to_var_int(i)))
|
||||
|
||||
|
||||
|
||||
1
tests/test/raw_block.txt
Normal file
1
tests/test/raw_block.txt
Normal file
File diff suppressed because one or more lines are too long
@ -1,7 +1,11 @@
|
||||
import unittest
|
||||
import os, sys
|
||||
parentPath = os.path.abspath("..")
|
||||
if parentPath not in sys.path:
|
||||
sys.path.insert(0, parentPath)
|
||||
from pybtc import blockchain
|
||||
from binascii import unhexlify
|
||||
from pybtc import address2hash
|
||||
from pybtc import address_to_hash
|
||||
|
||||
|
||||
class ScriptDeserializeTests(unittest.TestCase):
|
||||
@ -14,7 +18,7 @@ class ScriptDeserializeTests(unittest.TestCase):
|
||||
self.assertEqual(s.type, "P2PKH")
|
||||
self.assertEqual(s.ntype, 0)
|
||||
self.assertEqual(s.asm, "OP_DUP OP_HASH160 3520dd524f6ca66f63182bb23efff6cc8ee3ee63 OP_EQUALVERIFY OP_CHECKSIG")
|
||||
self.assertEqual(s.address[0], address2hash("15qvBdqSWQCuLQPXVoWViG2GvjeARmpYPw"))
|
||||
self.assertEqual(s.address[0], address_to_hash("15qvBdqSWQCuLQPXVoWViG2GvjeARmpYPw"))
|
||||
self.assertEqual(s.pattern, "OP_DUP OP_HASH160 <20> OP_EQUALVERIFY OP_CHECKSIG")
|
||||
self.assertEqual(s.op_sig_count, 1)
|
||||
|
||||
@ -24,7 +28,7 @@ class ScriptDeserializeTests(unittest.TestCase):
|
||||
self.assertEqual(s.type, "P2SH")
|
||||
self.assertEqual(s.ntype, 1)
|
||||
self.assertEqual(s.asm, "OP_HASH160 69f37572ab1b69f304f987b119e2450e0b71bf5c OP_EQUAL")
|
||||
self.assertEqual(s.address[0], address2hash("3BMEXVsYyfKB5h3m53XRSFHkqi1zPwsvcK"))
|
||||
self.assertEqual(s.address[0], address_to_hash("3BMEXVsYyfKB5h3m53XRSFHkqi1zPwsvcK"))
|
||||
self.assertEqual(s.pattern, "OP_HASH160 <20> OP_EQUAL")
|
||||
self.assertEqual(s.op_sig_count, 0)
|
||||
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import unittest
|
||||
import os, sys
|
||||
parentPath = os.path.abspath("..")
|
||||
if parentPath not in sys.path:
|
||||
sys.path.insert(0, parentPath)
|
||||
from pybtc import *
|
||||
from binascii import unhexlify
|
||||
from pybtc import address2hash as address2hash160
|
||||
from pybtc import address_to_hash as address2hash160
|
||||
|
||||
class SighashTests(unittest.TestCase):
|
||||
@classmethod
|
||||
|
||||
@ -1,31 +1,65 @@
|
||||
import unittest
|
||||
from pybtc import blockchain
|
||||
import os, sys
|
||||
import time
|
||||
parentPath = os.path.abspath("..")
|
||||
if parentPath not in sys.path:
|
||||
sys.path.insert(0, parentPath)
|
||||
from pybtc.tools import *
|
||||
from pybtc.hash import *
|
||||
from pybtc.transaction import *
|
||||
from binascii import unhexlify
|
||||
from pybtc import address2hash as address2hash160
|
||||
from pybtc import address_to_hash as address2hash160
|
||||
|
||||
def decode_block_tx(block):
|
||||
stream = get_stream(block)
|
||||
tx = dict()
|
||||
stream.seek(80)
|
||||
count = var_int_to_int(read_var_int(stream))
|
||||
for i in range(count):
|
||||
tx[i] = Transaction(stream)
|
||||
return tx
|
||||
|
||||
|
||||
class TransactionDeserializeTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
print("\nTesting Transaction class deserialization:\n")
|
||||
|
||||
def test_serialaize_and_perfomance(self):
|
||||
f = open('./test/raw_block.txt')
|
||||
fc = f.readline()
|
||||
qt = time.time()
|
||||
bt = decode_block_tx(fc[:-1])
|
||||
self.assertEqual(time.time() - qt < 1, 1)
|
||||
print("decode block tx count: %s time: %s" % (len(bt), time.time() - qt))
|
||||
for t in bt:
|
||||
raw_tx_legacy = bt[t].serialize(segwit=False)
|
||||
raw_tx_segwit = bt[t].serialize()
|
||||
bt[t] = bt[t].decode()
|
||||
# print(bt[t]["txId"], bt[t]["hash"], "segwit:",
|
||||
# True if "segwit" in bt[t] else False, end = " ")
|
||||
self.assertEqual(bt[t].serialize(segwit=False), raw_tx_legacy)
|
||||
self.assertEqual(bt[t].serialize(), raw_tx_segwit)
|
||||
self.assertEqual(rh2s(double_sha256(bt[t].serialize())), bt[t]["hash"])
|
||||
self.assertEqual(rh2s(double_sha256(bt[t].serialize(segwit=False))), bt[t]["txId"])
|
||||
# print("OK")
|
||||
|
||||
def test_segwit_deserialize(self):
|
||||
non_segwit_view = "020000000140d43a99926d43eb0e619bf0b3d83b4a31f60c176beecfb9d35bf45e54d0f7420100000017160014a4b4ca48de0b3fffc15404a1acdc8dbaae226955ffffffff0100e1f5050000000017a9144a1154d50b03292b3024370901711946cb7cccc38700000000"
|
||||
segwit_view = "0200000000010140d43a99926d43eb0e619bf0b3d83b4a31f60c176beecfb9d35bf45e54d0f7420100000017160014a4b4ca48de0b3fffc15404a1acdc8dbaae226955ffffffff0100e1f5050000000017a9144a1154d50b03292b3024370901711946cb7cccc387024830450221008604ef8f6d8afa892dee0f31259b6ce02dd70c545cfcfed8148179971876c54a022076d771d6e91bed212783c9b06e0de600fab2d518fad6f15a2b191d7fbd262a3e0121039d25ab79f41f75ceaf882411fd41fa670a4c672c23ffaf0e361a969cde0692e800000000"
|
||||
print("Deserialize Segwit transaction")
|
||||
ns = blockchain.Transaction.deserialize(non_segwit_view)
|
||||
s = blockchain.Transaction.deserialize(segwit_view)
|
||||
s.serialize(True,True)
|
||||
self.assertEqual(s.serialize(False,True), non_segwit_view)
|
||||
self.assertEqual(s.serialize(True,True), segwit_view)
|
||||
self.assertEqual(ns.serialize(False,True), non_segwit_view)
|
||||
ns = Transaction(non_segwit_view)
|
||||
s = Transaction(segwit_view)
|
||||
self.assertEqual(s.serialize(segwit=False, hex = True), non_segwit_view)
|
||||
self.assertEqual(s.serialize(segwit=True, hex = True), segwit_view)
|
||||
self.assertEqual(ns.serialize(segwit=False, hex = True), non_segwit_view)
|
||||
|
||||
non_segwit_view = "01000000060c02c24bbfefd94cdc4f58a3f83f93e05b14ad968ec6aba54190c3dcba6eef1b00000000da00483045022100f4dbf2ca7b5da97bd78818635d48004e6bf1a6f7e5e24bcecb7d93f554e49eaf02200a05025d93475b6372d14bd8fe8366fe10570ade772b19d124d3b0175b9f6eda0147304402202290feb53fc4cb077c5d3eed0ed5367fef4011ac708c1acaaa5003e4ed680ddf022012c52160ae6b85fc59ceed80c7cacd5358b80712371733de7c76fef552114ee60147522103ee30ea502d692ecfc79dfcb6fb2d6914fc70ba80db971beebacccdbaed40d7c52102f52db885d04dc43ca8562471759dd621b899faf508caba70963d9228bfd2415e52ae00000000dab020ee0a80a818e4d20a52aa7ba367a0a2d430d22c26ccb4572527e259e14a01000000d900473044022064745ac8cae859bb19305a550981b8d39b69efec55b9a423dca645cd3b5c845502205cf375839d7f056235feb550a8138a03e75fa140503a2ce61fe239a3bfe42145014730440220728b0393d5427d8abb56a608c6b1a0b14c5455f3abeb56ce8a5c7f70035af71d022052a99e4e389790b364f6180caf1523d6da2b3daabe85952705023be2b5409b360147522103e296937dbdafdae4d0a45b33d9a691b0c0e71d97bd2ffc82da895a251f74bd7e2103ead7ad0c398f928cbe851a6b387a5e74d139487caf4d4ac3dc3d478254dbbb4452ae0000000067a6c2e2f14fc412b3f5627fafac2fe43009bc403ec680839579444df2ce042b00000000da00483045022100d3bdc055fa5dcce335a1d572b1c3ccb8cc9ba91960c6361c77e29ded716e233102200e7ebb43fd39fb98c714098d4fda32d94cdbefdd96c0c918b788aacc6164953c0147304402202f4338d2710edb1960dcf7136411f065a16bee4e44b86604d64c660315bc55040220238c1c3216feb31051f7798297317819da1dfa830d24a6a9e38a37367a68ebd101475221037b2987df626510ce25e6ce5fdb716705e23fecb7398b2cbb0a1c0af7ca5da717210345e358653b4580b5bd68d263089a0a2bf9fcc1e145fcf2a3d4b9ab5cd7e1a76752ae000000004f28d63103dfb86a5d92d2daf328bbb35d72239766a5853b7076a90d1745813200000000da00483045022100e89ac8215ee87186de284c419b2522ebfb2ecb8063d0f91942f2ad63f383d3d4022036485902bb1f2e0b2cc645aab8781def27f25e91d8256d48dd48d5cfca1a21c20147304402201449379f1d57f2b7ad1dc0882f59627287a6c32180ffa7637941b0eaa666dd4b022028eb0eed77e1b92de046098c855834a5feeadea55d17160bc6d11d47184e8b51014752210283db605dc305201ab9be509a22d2c83b388002fb54ecd82d86efe83c0a1d35822103146f745eff0ae31fe899aafd27d51d2c0f5b0c03f2f47b3c65bb26ec7581ad8652ae0000000021cb3b00d1f22455e76e86872e00ef556578bcc112071e6a5b4ac02ab682fdb301000000232200206ea344e9a4a8f8a8983479af2ae3ed29fab153955af14457780a304a6832b9c50000000016dcc4b40a514c43ed61d6c01a9006d7f21a6d30b99b3e580d21578e35002502000000002322002049ea1f7c280b32fee0dce2e1801df2218df59d64614c4fe76c043ee2c80116700000000002005ed0b20000000017a91495c5c19257aa52bd4b702ba1a5e29b8d72a75a3a876d6b4e010000000017a91487b6255a5df746188f0bd22ed0194a40ec98f2de87be810700"
|
||||
segwit_view = "010000000001060c02c24bbfefd94cdc4f58a3f83f93e05b14ad968ec6aba54190c3dcba6eef1b00000000da00483045022100f4dbf2ca7b5da97bd78818635d48004e6bf1a6f7e5e24bcecb7d93f554e49eaf02200a05025d93475b6372d14bd8fe8366fe10570ade772b19d124d3b0175b9f6eda0147304402202290feb53fc4cb077c5d3eed0ed5367fef4011ac708c1acaaa5003e4ed680ddf022012c52160ae6b85fc59ceed80c7cacd5358b80712371733de7c76fef552114ee60147522103ee30ea502d692ecfc79dfcb6fb2d6914fc70ba80db971beebacccdbaed40d7c52102f52db885d04dc43ca8562471759dd621b899faf508caba70963d9228bfd2415e52ae00000000dab020ee0a80a818e4d20a52aa7ba367a0a2d430d22c26ccb4572527e259e14a01000000d900473044022064745ac8cae859bb19305a550981b8d39b69efec55b9a423dca645cd3b5c845502205cf375839d7f056235feb550a8138a03e75fa140503a2ce61fe239a3bfe42145014730440220728b0393d5427d8abb56a608c6b1a0b14c5455f3abeb56ce8a5c7f70035af71d022052a99e4e389790b364f6180caf1523d6da2b3daabe85952705023be2b5409b360147522103e296937dbdafdae4d0a45b33d9a691b0c0e71d97bd2ffc82da895a251f74bd7e2103ead7ad0c398f928cbe851a6b387a5e74d139487caf4d4ac3dc3d478254dbbb4452ae0000000067a6c2e2f14fc412b3f5627fafac2fe43009bc403ec680839579444df2ce042b00000000da00483045022100d3bdc055fa5dcce335a1d572b1c3ccb8cc9ba91960c6361c77e29ded716e233102200e7ebb43fd39fb98c714098d4fda32d94cdbefdd96c0c918b788aacc6164953c0147304402202f4338d2710edb1960dcf7136411f065a16bee4e44b86604d64c660315bc55040220238c1c3216feb31051f7798297317819da1dfa830d24a6a9e38a37367a68ebd101475221037b2987df626510ce25e6ce5fdb716705e23fecb7398b2cbb0a1c0af7ca5da717210345e358653b4580b5bd68d263089a0a2bf9fcc1e145fcf2a3d4b9ab5cd7e1a76752ae000000004f28d63103dfb86a5d92d2daf328bbb35d72239766a5853b7076a90d1745813200000000da00483045022100e89ac8215ee87186de284c419b2522ebfb2ecb8063d0f91942f2ad63f383d3d4022036485902bb1f2e0b2cc645aab8781def27f25e91d8256d48dd48d5cfca1a21c20147304402201449379f1d57f2b7ad1dc0882f59627287a6c32180ffa7637941b0eaa666dd4b022028eb0eed77e1b92de046098c855834a5feeadea55d17160bc6d11d47184e8b51014752210283db605dc305201ab9be509a22d2c83b388002fb54ecd82d86efe83c0a1d35822103146f745eff0ae31fe899aafd27d51d2c0f5b0c03f2f47b3c65bb26ec7581ad8652ae0000000021cb3b00d1f22455e76e86872e00ef556578bcc112071e6a5b4ac02ab682fdb301000000232200206ea344e9a4a8f8a8983479af2ae3ed29fab153955af14457780a304a6832b9c50000000016dcc4b40a514c43ed61d6c01a9006d7f21a6d30b99b3e580d21578e35002502000000002322002049ea1f7c280b32fee0dce2e1801df2218df59d64614c4fe76c043ee2c80116700000000002005ed0b20000000017a91495c5c19257aa52bd4b702ba1a5e29b8d72a75a3a876d6b4e010000000017a91487b6255a5df746188f0bd22ed0194a40ec98f2de87000000000400473044022100d0d2ded141c9369bcc99de23d3d41d1d99d6cff47126df1b0c4d4797f947eacf021f790f1c112b3425ebc3251d719aae6ef0f9830b688585275591a5353f1f973801483045022100bf06c762e6ab64258d2f2777a66fe32ddd8f36e232b80bf5afa6ff9b9aa73ee0022049caf991fce808e60a9b17499f5e0dc11f6163e3ef7bca8109b72b5695d674210147522103edd556806048b319d71f43466c4415001bb32d8afe3aac06532d3ac210fd0e86210215e16727cf1389b4ee377487385f3ec595841a6bb747eb9c3a5cd559e9b1c8dc52ae040047304402204e9cc87526e148d236d692fa70104d26b8df632f30f4e3be38a2e99cec76d0f80220354ae575c3537c0ad2399a6037a9164b0cb147b12f262efc906649ca7950e2eb0147304402203553bcd1565804ec71c997c87006bd91c639b74a004b19a239c7f551aab5635a0220753f74e065c0b7cdf67d16b00f6a20dda7159a49f20aa493a7889b2851b2fea30147522103b09ac1fa65a55fa4feadea57c4cf417d7490065d8b844ada60c242a441e0e3a42103c0625169b46dbbde3492db7c62f1be8f582131467620cef17335306bad7ef88a52aebe810700"
|
||||
print("Deserialize Segwit transaction")
|
||||
ns = blockchain.Transaction.deserialize(non_segwit_view)
|
||||
s = blockchain.Transaction.deserialize(segwit_view)
|
||||
s.serialize(True, True)
|
||||
self.assertEqual(s.serialize(False, True), non_segwit_view)
|
||||
self.assertEqual(s.serialize(True, True), segwit_view)
|
||||
self.assertEqual(ns.serialize(False, True), non_segwit_view)
|
||||
ns = Transaction(non_segwit_view)
|
||||
s = Transaction(segwit_view)
|
||||
self.assertEqual(s.serialize(segwit=False,hex = True), non_segwit_view)
|
||||
self.assertEqual(s.serialize(segwit=True, hex = True), segwit_view)
|
||||
self.assertEqual(ns.serialize(segwit=False, hex = True), non_segwit_view)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user