merging with updated origin/2.0 branch
This commit is contained in:
commit
571793359c
89
README.md
89
README.md
@ -1,88 +1,3 @@
|
||||
# pybtc
|
||||
Python bitcoin library
|
||||
|
||||
|
||||
### Basic Examples
|
||||
|
||||
#### Create private key
|
||||
|
||||
>>> from pybtc import *
|
||||
>>> create_priv()
|
||||
b'\xc8\xf5tGf\x00+4\x1c\xe3\xb6\x00\xf4\x14w\x1d\xf0{jiY&4`v\xd4\tmv!\x0f\x1f'
|
||||
>>>
|
||||
>>> priv = create_priv()
|
||||
>>> priv
|
||||
b'_`\xd7@\x9e\xdb\xbbB5O%@\xd6\x92\xb1\x0e*\xcd\xb6\x89!\xa3JE\xb0\xb6:\x8c\x04\x88\xc9\xa5'
|
||||
>>>
|
||||
>>> priv2WIF(priv)
|
||||
'KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW'
|
||||
>>>
|
||||
>>> priv2WIF(priv, compressed = False) # Mainnet compressed WIF format
|
||||
'5JYHtgBjYbLT3ZkhGHHCivscdMdDKeVTZBgq5ZK51fyKpqKDhYv' # Mainnet uncompressed WIF format
|
||||
>>>
|
||||
>>> priv2WIF(priv, testnet = True)
|
||||
'cQn71zxEDWF77m386rfe7PHTshLF3kaJH6KGKY5GD5fcLsCqpPbg'
|
||||
>>>
|
||||
>>> priv2WIF(priv, compressed = True, testnet = True) # Testnet compressed WIF format
|
||||
'cQn71zxEDWF77m386rfe7PHTshLF3kaJH6KGKY5GD5fcLsCqpPbg'
|
||||
>>>
|
||||
>>> priv2WIF(priv, compressed = False, testnet = True) # Testnet uncompressed WIF format
|
||||
'92JvUR1H8pQb1dFytdB7bXRaH1yvUp2eu8YnABfaMQiNbuKiPVL'
|
||||
>>>
|
||||
>>> WIF2priv("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW")
|
||||
b'_`\xd7@\x9e\xdb\xbbB5O%@\xd6\x92\xb1\x0e*\xcd\xb6\x89!\xa3JE\xb0\xb6:\x8c\x04\x88\xc9\xa5'
|
||||
>>>
|
||||
|
||||
#### Public key from private key
|
||||
|
||||
>>> from pybtc import *
|
||||
>>> priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW")
|
||||
b'\x02\xb1-\xc2\x03u\xda\x00*7t\xb9c\xe4A\xdb\x1c\xe0\x89\xb8W\x13\x86\xbe\x82\xee(\x11nrj\xb06'
|
||||
>>>
|
||||
>>> priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW", hex = True)
|
||||
'02b12dc20375da002a3774b963e441db1ce089b8571386be82ee28116e726ab036'
|
||||
>>>
|
||||
>>> priv = WIF2priv("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW")
|
||||
>>> priv
|
||||
b'_`\xd7@\x9e\xdb\xbbB5O%@\xd6\x92\xb1\x0e*\xcd\xb6\x89!\xa3JE\xb0\xb6:\x8c\x04\x88\xc9\xa5'
|
||||
>>>
|
||||
>>> priv2pub(priv, hex = True)
|
||||
'02b12dc20375da002a3774b963e441db1ce089b8571386be82ee28116e726ab036'
|
||||
>>>
|
||||
|
||||
#### Address from public key/private key
|
||||
|
||||
>>> from pybtc import *
|
||||
>>> # address in bech32 format
|
||||
...
|
||||
>>> pub2address(priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW"))
|
||||
'bc1q3hs6985qftzrvfl7aqcshsf7equapuuxzr2kcv'
|
||||
>>>
|
||||
>>> # address in legacy format
|
||||
...
|
||||
>>> pub2address(priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW"), witness_version = None)
|
||||
'1DwCaTcMTT5kZmH4wCevDe5nyzffi2Bz9p'
|
||||
>>>
|
||||
>>> # uncompressed public key deprecated for bech32 segwit addresses fromat
|
||||
...
|
||||
>>> pub2address(priv2pub("5JYHtgBjYbLT3ZkhGHHCivscdMdDKeVTZBgq5ZK51fyKpqKDhYv"))
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
File "/usr/local/lib/python3.6/site-packages/pybtc/tools.py", line 233, in pub2address
|
||||
assert len(pubkey) == 33
|
||||
AssertionError
|
||||
>>>
|
||||
>>> # uncompressed public key legacy format
|
||||
...
|
||||
>>> pub2address(priv2pub("5JYHtgBjYbLT3ZkhGHHCivscdMdDKeVTZBgq5ZK51fyKpqKDhYv"), witness_version = None)
|
||||
'1EbTeoa1QgZaSHZFznrhNdKrRbbQupVwuZ'
|
||||
>>>
|
||||
>>> # testnet addresses
|
||||
...
|
||||
>>> pub2address(priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW"), testnet = True)
|
||||
'tb1q3hs6985qftzrvfl7aqcshsf7equapuuxg939rl'
|
||||
>>>
|
||||
>>> pub2address(priv2pub("KzR7Z5xNnSYqxKZriSrWk4nQFU2qPJUcD4AoD7ckhy1c68A4zvkW"), witness_version = None, testnet = True)
|
||||
'mtT9sWhLGUX1LskgemdJ3ZJ7qzGNaygcXP'
|
||||
>>>
|
||||
<img src="doc/img/pybtc.png" width="100">
|
||||
|
||||
## Python bitcoin library
|
||||
|
||||
BIN
doc/img/pybtc.png
Normal file
BIN
doc/img/pybtc.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
@ -1,6 +1,7 @@
|
||||
# from .tools import *
|
||||
# from .opcodes import *
|
||||
from .tools import *
|
||||
from .opcodes import *
|
||||
from .consensus import *
|
||||
from .blockchain import *
|
||||
from .transaction import *
|
||||
from .address import *
|
||||
|
||||
version = "2.0.1"
|
||||
|
||||
104
pybtc/address.py
Normal file
104
pybtc/address.py
Normal file
@ -0,0 +1,104 @@
|
||||
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)
|
||||
28
pybtc/block.py
Normal file
28
pybtc/block.py
Normal file
@ -0,0 +1,28 @@
|
||||
from .tools import *
|
||||
from .transaction import Transaction
|
||||
from struct import pack, unpack
|
||||
|
||||
|
||||
class Block(dict):
|
||||
def __init__(self, block):
|
||||
s = get_stream(block)
|
||||
self["header"] = s.read(80)
|
||||
self["hash"] = double_sha256(self["header"])
|
||||
self["version"] = unpack("<L", s.read(4))
|
||||
self["previousBlockHash"] = s.read(32)
|
||||
self["merkleRoot"] = s.read(32)
|
||||
self["time"] = unpack("<L", s.read(4))
|
||||
self["bits"] = s.read(4),
|
||||
self["nonce"] = unpack("<L", s.read(4))
|
||||
s.seek(-80, 1)
|
||||
# self["tx"] = {i: Transaction(s)
|
||||
# for i in range(var_int_to_int(read_var_int(s)))}
|
||||
self["weight"] = 0
|
||||
self["size"] = 0
|
||||
self["strippedSize"] = 0
|
||||
self["height"] = 0
|
||||
self["difficulty"] = 0
|
||||
self["targetDifficulty"] = 0
|
||||
self["target"] = 0
|
||||
|
||||
|
||||
@ -6,262 +6,13 @@ 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():
|
||||
class OLDTransaction():
|
||||
def __init__(self, version = 1, tx_in = [], tx_out = [] , lock_time = 0,
|
||||
hash=None, size = 0, timestamp = None,
|
||||
marker = None, flag = None, witness = [],
|
||||
@ -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)
|
||||
|
||||
@ -659,9 +410,10 @@ class Transaction():
|
||||
witness = witness, whash = wtx_id, vsize = vsize)
|
||||
|
||||
|
||||
class Block():
|
||||
class OLDBlock():
|
||||
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))
|
||||
@ -749,7 +502,6 @@ class Block():
|
||||
extranonce_start = len_coinbase + extranonce_start
|
||||
return tx[:44 + extranonce_start], tx[44 + extranonce_start + extranonce_size:]
|
||||
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream):
|
||||
stream = get_stream(stream)
|
||||
@ -762,11 +514,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 +531,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 +574,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 +660,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"]
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
from secp256k1 import lib as secp256k1
|
||||
from secp256k1 import ffi
|
||||
import random
|
||||
import os
|
||||
|
||||
ROOT_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
BIP0039_DIR = os.path.normpath(os.path.join(ROOT_DIR, 'bip-0039'))
|
||||
|
||||
MAX_AMOUNT = 2100000000000000
|
||||
SIGHASH_ALL = 0x00000001
|
||||
SIGHASH_NONE = 0x00000002
|
||||
SIGHASH_SINGLE = 0x00000003
|
||||
@ -85,3 +85,4 @@ MAINNET_PUBLIC_WALLET_VERSION = b'\x04\x88\xB2\x1E'
|
||||
TESTNET_PRIVATE_WALLET_VERSION = b'\x04\x35\x83\x94'
|
||||
TESTNET_PUBLIC_WALLET_VERSION = b'\x04\x35\x87\xCF'
|
||||
FIRST_HARDENED_CHILD = 0x80000000
|
||||
|
||||
|
||||
@ -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
|
||||
@ -38,12 +36,15 @@ def rebasebits(data, frombits, tobits, pad=True):
|
||||
raise Exception("invalid padding")
|
||||
return ret
|
||||
|
||||
|
||||
def rebase_5_to_8(data, pad = True):
|
||||
return rebasebits(data, 5, 8, pad)
|
||||
|
||||
|
||||
def rebase_8_to_5(data, pad = True):
|
||||
return rebasebits(data, 8, 5, pad)
|
||||
|
||||
|
||||
def rebase_32_to_5(data):
|
||||
if type(data) == bytes:
|
||||
data = data.decode()
|
||||
@ -55,12 +56,14 @@ def rebase_32_to_5(data):
|
||||
raise Exception("Non base32 characters")
|
||||
return b
|
||||
|
||||
|
||||
def rebase_5_to_32(data, bytes = True):
|
||||
r = bytearray()
|
||||
for i in data:
|
||||
r.append(base32_int_map[i])
|
||||
return r.decode() if not bytes else r
|
||||
|
||||
|
||||
def bech32_polymod(values):
|
||||
"""Internal function that computes the Bech32 checksum."""
|
||||
generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
|
||||
@ -72,6 +75,7 @@ def bech32_polymod(values):
|
||||
chk ^= generator[i] if ((top >> i) & 1) else 0
|
||||
return chk ^ 1
|
||||
|
||||
|
||||
def encode_base58(b):
|
||||
"""Encode bytes to a base58-encoded string"""
|
||||
# Convert big-endian bytes to integer
|
||||
@ -92,6 +96,7 @@ def encode_base58(b):
|
||||
break
|
||||
return b58_digits[0] * pad + res
|
||||
|
||||
|
||||
def decode_base58(s):
|
||||
"""Decode a base58-encoding string, returning bytes"""
|
||||
if not s:
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -6,7 +6,7 @@ from struct import pack, unpack
|
||||
from hashlib import pbkdf2_hmac
|
||||
from binascii import hexlify, unhexlify
|
||||
from .constants import *
|
||||
from .tools import priv2pub, is_valid_pub, encode_base58, decode_base58
|
||||
from .tools import private_to_public_key, is_valid_public_key, encode_base58, decode_base58
|
||||
from .hash import hmac_sha512, hash160, double_sha256, sha256, double_sha256
|
||||
|
||||
|
||||
@ -123,7 +123,7 @@ def create_parent_pubkey_hdwallet(master_key):
|
||||
version = TESTNET_PUBLIC_WALLET_VERSION
|
||||
else:
|
||||
version = MAINNET_PUBLIC_WALLET_VERSION
|
||||
pubkey = priv2pub(master_key['key'], True)
|
||||
pubkey = private_to_public_key(master_key['key'], True)
|
||||
return dict(version=version,
|
||||
key=pubkey,
|
||||
depth=master_key['depth'],
|
||||
@ -142,7 +142,7 @@ def create_child_privkey(key, child_idx):
|
||||
child_chain_code = expanded_privkey[32:]
|
||||
child_privkey = add_private_keys(expanded_privkey[:32], key['key'])
|
||||
if validate_private_key(child_privkey):
|
||||
finger_print = hash160(priv2pub(key['key']))[:4]
|
||||
finger_print = hash160(private_to_public_key(key['key']))[:4]
|
||||
return dict(version=key['version'],
|
||||
key=child_privkey,
|
||||
depth=key['depth'] + 1,
|
||||
@ -159,9 +159,9 @@ def create_child_pubkey(key, child_idx):
|
||||
expanded_pubkey = create_expanded_key(key, child_idx)
|
||||
if expanded_pubkey:
|
||||
child_chain_code = expanded_pubkey[32:]
|
||||
ext_value = priv2pub(expanded_pubkey[:32])
|
||||
ext_value = private_to_public_key(expanded_pubkey[:32])
|
||||
child_pubkey = add_public_keys(ext_value, key['key'])
|
||||
if is_valid_pub(child_pubkey):
|
||||
if is_valid_public_key(child_pubkey):
|
||||
finger_print = hash160(key['key'])[:4]
|
||||
return dict(version=key['version'],
|
||||
key=child_pubkey,
|
||||
@ -180,7 +180,7 @@ def create_expanded_key(key, child_idx):
|
||||
seed = key['key'] + pack('I', child_idx)
|
||||
return hmac_sha512(key['chain_code'], seed)
|
||||
elif key.get('is_private') and child_idx < FIRST_HARDENED_CHILD:
|
||||
public_key = priv2pub(key['key'])
|
||||
public_key = private_to_public_key(key['key'])
|
||||
seed = public_key + pack('I', child_idx)
|
||||
return hmac_sha512(key['chain_code'], seed)
|
||||
return None
|
||||
|
||||
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 )
|
||||
|
||||
556
pybtc/tools.py
556
pybtc/tools.py
@ -1,61 +1,61 @@
|
||||
import hashlib
|
||||
from binascii import hexlify, unhexlify
|
||||
import time
|
||||
import struct
|
||||
import hmac
|
||||
from secp256k1 import ffi
|
||||
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)
|
||||
i = int((time.time()%0.01)*100000)
|
||||
h = a.to_bytes(32,byteorder="big")
|
||||
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:
|
||||
h = hashlib.sha256(h).digest()
|
||||
if i>1: i -= 1
|
||||
if i > 1:
|
||||
i -= 1
|
||||
else:
|
||||
if int.from_bytes(h,byteorder="big")<MAX_INT_PRIVATE_KEY:
|
||||
if int.from_bytes(h, byteorder="big") < MAX_INT_PRIVATE_KEY:
|
||||
break
|
||||
if hex:
|
||||
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):
|
||||
#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
|
||||
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:
|
||||
h = MAINNET_PRIVATE_KEY_BYTE_PREFIX + h
|
||||
if compressed: h += b'\x01'
|
||||
if compressed:
|
||||
h += b'\x01'
|
||||
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):
|
||||
|
||||
def is_wif_valid(wif):
|
||||
assert type(wif) == str
|
||||
if wif[0] not in PRIVATE_KEY_PREFIX_LIST:
|
||||
return False
|
||||
try:
|
||||
@ -73,18 +73,19 @@ 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)
|
||||
elif type(private_key) == str:
|
||||
if not is_WIF_valid(private_key):
|
||||
if not is_wif_valid(private_key):
|
||||
private_key = unhexlify(private_key)
|
||||
else:
|
||||
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 +100,8 @@ 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 +117,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:
|
||||
@ -126,7 +128,7 @@ def hash2address(address_hash, testnet = False,
|
||||
prefix = TESTNET_ADDRESS_BYTE_PREFIX
|
||||
else:
|
||||
prefix = MAINNET_ADDRESS_BYTE_PREFIX
|
||||
address_hash = prefix + address_hash
|
||||
address_hash = prefix + address_hash
|
||||
address_hash += double_sha256(address_hash)[:4]
|
||||
return encode_base58(address_hash)
|
||||
else:
|
||||
@ -136,7 +138,7 @@ def hash2address(address_hash, testnet = False,
|
||||
prefix = TESTNET_SCRIPT_ADDRESS_BYTE_PREFIX
|
||||
else:
|
||||
prefix = MAINNET_SCRIPT_ADDRESS_BYTE_PREFIX
|
||||
address_hash = prefix + address_hash
|
||||
address_hash = prefix + address_hash
|
||||
address_hash += double_sha256(address_hash)[:4]
|
||||
return encode_base58(address_hash)
|
||||
if testnet:
|
||||
@ -145,15 +147,15 @@ def hash2address(address_hash, testnet = False,
|
||||
else:
|
||||
prefix = MAINNET_SEGWIT_ADDRESS_BYTE_PREFIX
|
||||
hrp = MAINNET_SEGWIT_ADDRESS_PREFIX
|
||||
address_hash = witness_version.to_bytes(1, "big") + rebase_8_to_5( address_hash)
|
||||
address_hash = witness_version.to_bytes(1, "big") + rebase_8_to_5(address_hash)
|
||||
checksum = bech32_polymod(prefix + address_hash + b"\x00" * 6)
|
||||
checksum = rebase_8_to_5(checksum.to_bytes(5, "big"))[2:]
|
||||
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]
|
||||
h = decode_base58(address)[1:-4]
|
||||
elif address[:2] in (MAINNET_SEGWIT_ADDRESS_PREFIX,
|
||||
TESTNET_SEGWIT_ADDRESS_PREFIX):
|
||||
address = address.split("1")[1]
|
||||
@ -165,18 +167,20 @@ def address2hash(address, hex = False):
|
||||
else:
|
||||
return h
|
||||
|
||||
|
||||
def get_witness_version(address):
|
||||
address = address.split("1")[1]
|
||||
h = rebase_32_to_5(address)
|
||||
return h[0]
|
||||
|
||||
def address_type(address, num = False):
|
||||
|
||||
def address_type(address, num=False):
|
||||
if address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX,
|
||||
MAINNET_SCRIPT_ADDRESS_PREFIX):
|
||||
t = 'P2SH'
|
||||
elif address[0] in (MAINNET_ADDRESS_PREFIX,
|
||||
TESTNET_ADDRESS_PREFIX,
|
||||
TESTNET_ADDRESS_PREFIX_2):
|
||||
TESTNET_ADDRESS_PREFIX,
|
||||
TESTNET_ADDRESS_PREFIX_2):
|
||||
t = 'P2PKH'
|
||||
elif address[:2] in (MAINNET_SEGWIT_ADDRESS_PREFIX,
|
||||
TESTNET_SEGWIT_ADDRESS_PREFIX):
|
||||
@ -190,7 +194,8 @@ 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 +203,43 @@ 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,
|
||||
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,
|
||||
MAINNET_SEGWIT_ADDRESS_PREFIX):
|
||||
h = address2hash(address)
|
||||
return OPCODE["OP_0"] + bytes([len(h)]) + h
|
||||
raise Exception("Unknown address")
|
||||
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):
|
||||
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 = 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,21 +250,136 @@ def pub2address(pubkey, testnet = False,
|
||||
if witness_version is not None:
|
||||
assert len(pubkey) == 33
|
||||
h = hash160(pubkey)
|
||||
return hash2address(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)
|
||||
return hash_to_address(h, testnet=testnet,
|
||||
script_hash=p2sh_p2wpkh,
|
||||
witness_version=witness_version)
|
||||
|
||||
|
||||
def is_address_valid(address, testnet = False):
|
||||
def parse_script(script, segwit=True):
|
||||
if not script:
|
||||
return {"nType": 7, "type": "NON_STANDARD", "reqSigs": 0, "script": b""}
|
||||
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"]:
|
||||
try:
|
||||
s += 1 + script[s + 1]
|
||||
except:
|
||||
break
|
||||
elif script[s] == OPCODE["OP_PUSHDATA2"]:
|
||||
try:
|
||||
s += 2 + struct.unpack('<H', script[s: s + 2])[0]
|
||||
except:
|
||||
break
|
||||
elif script[s] == OPCODE["OP_PUSHDATA4"]:
|
||||
try:
|
||||
s += 4 + struct.unpack('<L', script[s: s + 4])[0]
|
||||
except:
|
||||
break
|
||||
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):
|
||||
if not address or type(address) != str:
|
||||
return False
|
||||
if address[0] in (MAINNET_ADDRESS_PREFIX,
|
||||
@ -265,7 +397,8 @@ def is_address_valid(address, testnet = False):
|
||||
MAINNET_SCRIPT_ADDRESS_PREFIX):
|
||||
return False
|
||||
h = decode_base58(address)
|
||||
if len(h) != 25: return False
|
||||
if len(h) != 25:
|
||||
return False
|
||||
checksum = h[-4:]
|
||||
if double_sha256(h[:-4])[:4] != checksum:
|
||||
return False
|
||||
@ -284,10 +417,10 @@ def is_address_valid(address, testnet = False):
|
||||
if not i.isupper() or i not in base32charset_upcase:
|
||||
return False
|
||||
else:
|
||||
if i.isupper() or i not in base32charset:
|
||||
return False
|
||||
if i.isupper() or i not in base32charset:
|
||||
return False
|
||||
payload = payload.lower()
|
||||
prefix = prefix.lower()
|
||||
prefix = prefix.lower()
|
||||
if testnet:
|
||||
if prefix != TESTNET_SEGWIT_ADDRESS_PREFIX:
|
||||
return False
|
||||
@ -306,30 +439,25 @@ def is_address_valid(address, testnet = False):
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# ECDSA
|
||||
#
|
||||
|
||||
def verify_signature(sig, pubKey, msg):
|
||||
def verify_signature(sig, pub_key, msg):
|
||||
if type(sig) != bytes:
|
||||
if type(sig) == bytearray:
|
||||
sig = bytes(sig)
|
||||
|
||||
elif type(sig) == str:
|
||||
sig = unhexlify(sig)
|
||||
else :
|
||||
else:
|
||||
raise TypeError("signature must be a bytes or hex encoded string")
|
||||
if type(pubKey) != bytes:
|
||||
if type(pubKey) == bytearray:
|
||||
pubKey = bytes(pubKey)
|
||||
|
||||
elif type(pubKey) == str:
|
||||
pubKey = unhexlify(pubKey)
|
||||
else :
|
||||
if type(pub_key) != bytes:
|
||||
if type(pub_key) == bytearray:
|
||||
pub_key = bytes(pub_key)
|
||||
elif type(pub_key) == str:
|
||||
pub_key = unhexlify(pub_key)
|
||||
else:
|
||||
raise TypeError("public key must be a bytes or hex encoded string")
|
||||
|
||||
if type(msg) != bytes:
|
||||
if type(msg) == bytearray:
|
||||
msg = bytes(msg)
|
||||
@ -337,17 +465,17 @@ def verify_signature(sig, pubKey, msg):
|
||||
msg = unhexlify(msg)
|
||||
else:
|
||||
raise TypeError("message must be a bytes or hex encoded string")
|
||||
|
||||
raw_sig = ffi.new('secp256k1_ecdsa_signature *')
|
||||
raw_pubkey = ffi.new('secp256k1_pubkey *')
|
||||
if not secp256k1.secp256k1_ecdsa_signature_parse_der(ECDSA_CONTEXT_VERIFY , raw_sig, sig, len(sig)):
|
||||
if not secp256k1.secp256k1_ecdsa_signature_parse_der(ECDSA_CONTEXT_VERIFY, raw_sig, sig, len(sig)):
|
||||
raise TypeError("signature must be DER encoded")
|
||||
if not secp256k1.secp256k1_ec_pubkey_parse(ECDSA_CONTEXT_VERIFY, raw_pubkey, pubKey, len(pubKey)):
|
||||
if not secp256k1.secp256k1_ec_pubkey_parse(ECDSA_CONTEXT_VERIFY, raw_pubkey, pub_key, len(pub_key)):
|
||||
raise TypeError("public key format error")
|
||||
result = secp256k1.secp256k1_ecdsa_verify(ECDSA_CONTEXT_VERIFY, raw_sig, msg, raw_pubkey)
|
||||
return True if result else False
|
||||
|
||||
def sign_message(msg, private_key, hex = False):
|
||||
|
||||
def sign_message(msg, private_key, hex=False):
|
||||
"""
|
||||
:param msg: message to sign
|
||||
:param private_key: private key (bytes, hex encoded string)
|
||||
@ -362,7 +490,7 @@ def sign_message(msg, private_key, hex = False):
|
||||
msg = unhexlify(msg)
|
||||
else :
|
||||
raise TypeError("message must be a bytes or hex encoded string")
|
||||
if type(private_key)!= bytes:
|
||||
if type(private_key) != bytes:
|
||||
if type(private_key) == bytearray:
|
||||
private_key = bytes(private_key)
|
||||
elif type(private_key) == str:
|
||||
@ -370,16 +498,19 @@ def sign_message(msg, private_key, hex = False):
|
||||
else:
|
||||
raise TypeError("private key must be a bytes or hex encoded string")
|
||||
raw_sig = ffi.new('secp256k1_ecdsa_signature *')
|
||||
signed = secp256k1.secp256k1_ecdsa_sign(ECDSA_CONTEXT_SIGN, raw_sig, msg, private_key, ffi.NULL, ffi.NULL)
|
||||
signed = secp256k1.secp256k1_ecdsa_sign(ECDSA_CONTEXT_SIGN, raw_sig, msg,
|
||||
private_key, ffi.NULL, ffi.NULL)
|
||||
assert signed == 1
|
||||
len_sig = 74
|
||||
output = ffi.new('unsigned char[%d]' % len_sig)
|
||||
outputlen = ffi.new('size_t *', len_sig)
|
||||
res = secp256k1.secp256k1_ecdsa_signature_serialize_der(ECDSA_CONTEXT_SIGN, output, outputlen, raw_sig)
|
||||
res = secp256k1.secp256k1_ecdsa_signature_serialize_der(ECDSA_CONTEXT_SIGN,
|
||||
output, outputlen, raw_sig)
|
||||
assert res == 1
|
||||
signature = bytes(ffi.buffer(output, outputlen[0]))
|
||||
signature = bytes(ffi.buffer(output, outputlen[0]))
|
||||
return hexlify(signature).decode() if hex else signature
|
||||
|
||||
|
||||
def is_valid_signature_encoding(sig):
|
||||
# Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
|
||||
# * total-length: 1-byte length descriptor of everything that follows,
|
||||
@ -392,7 +523,6 @@ def is_valid_signature_encoding(sig):
|
||||
# * S: arbitrary-length big-endian encoded S value. The same rules apply.
|
||||
# * sighash: 1-byte value indicating what data is hashed (not part of the DER
|
||||
# signature)
|
||||
|
||||
length = len(sig)
|
||||
# Minimum and maximum size constraints.
|
||||
if (length < 9) or (length > 73):
|
||||
@ -404,41 +534,41 @@ def is_valid_signature_encoding(sig):
|
||||
if sig[1] != (length - 3):
|
||||
return False
|
||||
# Extract the length of the R element.
|
||||
lenR = sig[3]
|
||||
len_r = sig[3]
|
||||
# Make sure the length of the S element is still inside the signature.
|
||||
if (5 + lenR) >= length:
|
||||
if (5 + len_r) >= length:
|
||||
return False
|
||||
# Extract the length of the S element.
|
||||
lenS = sig[5 + lenR]
|
||||
len_s = sig[5 + len_r]
|
||||
# Verify that the length of the signature matches the sum of the length
|
||||
# of the elements.
|
||||
if (lenR + lenS + 7) != length:
|
||||
if (len_r + len_s + 7) != length:
|
||||
return False
|
||||
# Check whether the R element is an integer.
|
||||
if sig[2] != 0x02:
|
||||
return False
|
||||
# Zero-length integers are not allowed for R.
|
||||
if lenR == 0:
|
||||
if len_r == 0:
|
||||
return False
|
||||
# Negative numbers are not allowed for R.
|
||||
if sig[4] & 0x80:
|
||||
return False
|
||||
# Null bytes at the start of R are not allowed, unless R would
|
||||
# otherwise be interpreted as a negative number.
|
||||
if (lenR > 1) and (sig[4] == 0x00) and (not sig[5] & 0x80):
|
||||
if (len_r > 1) and (sig[4] == 0x00) and (not sig[5] & 0x80):
|
||||
return False
|
||||
# Check whether the S element is an integer.
|
||||
if sig[lenR + 4] != 0x02:
|
||||
if sig[len_r + 4] != 0x02:
|
||||
return False
|
||||
# Zero-length integers are not allowed for S.
|
||||
if lenS == 0:
|
||||
if len_s == 0:
|
||||
return False
|
||||
# Negative numbers are not allowed for S.
|
||||
if sig[lenR + 6] & 0x80:
|
||||
if sig[len_r + 6] & 0x80:
|
||||
return False
|
||||
# Null bytes at the start of S are not allowed, unless S would otherwise be
|
||||
# interpreted as a negative number.
|
||||
if (lenS > 1) and (sig[lenR + 6] == 0x00) and (not sig[lenR + 7] & 0x80):
|
||||
if (len_s > 1) and (sig[len_r + 6] == 0x00) and (not sig[len_r + 7] & 0x80):
|
||||
return False
|
||||
return True
|
||||
|
||||
@ -447,41 +577,30 @@ 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):
|
||||
# raw hash to string
|
||||
return hexlify(tthash[::-1]).decode()
|
||||
|
||||
|
||||
def s2rh(hash_string):
|
||||
# string to raw hash
|
||||
return unhexlify(hash_string)[::-1]
|
||||
|
||||
|
||||
def s2rh_step4(hash_string):
|
||||
h = unhexlify(hash_string)
|
||||
return reverse_hash(h)
|
||||
|
||||
|
||||
def reverse_hash(h):
|
||||
return struct.pack('>IIIIIIII', *struct.unpack('>IIIIIIII', h)[::-1])[::-1]
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
def merkleroot(tx_hash_list):
|
||||
def merkle_root(tx_hash_list):
|
||||
tx_hash_list = list(tx_hash_list)
|
||||
if len(tx_hash_list) == 1:
|
||||
return tx_hash_list[0]
|
||||
@ -499,6 +618,7 @@ def merkleroot(tx_hash_list):
|
||||
else:
|
||||
return new_hash_list[0]
|
||||
|
||||
|
||||
def merkle_branches(tx_hash_list):
|
||||
tx_hash_list = list(tx_hash_list)
|
||||
branches = []
|
||||
@ -522,6 +642,7 @@ def merkle_branches(tx_hash_list):
|
||||
branches.append(new_hash_list.pop(0))
|
||||
return branches
|
||||
|
||||
|
||||
def merkleroot_from_branches(merkle_branches, coinbase_hash_bin):
|
||||
merkle_root = coinbase_hash_bin
|
||||
for h in merkle_branches:
|
||||
@ -529,75 +650,155 @@ 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 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 bytes_needed(n):
|
||||
if n == 0:
|
||||
return 1
|
||||
return math.ceil(n.bit_length()/8)
|
||||
|
||||
|
||||
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
|
||||
def int_to_bytes(i, byteorder='big'):
|
||||
return i.to_bytes(bytes_needed(i), byteorder=byteorder, signed=False)
|
||||
|
||||
|
||||
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 bytes_to_int(i, byteorder='big'):
|
||||
return int.from_bytes(i, byteorder=byteorder, signed=False)
|
||||
|
||||
|
||||
def to_var_int(i):
|
||||
if i < 253:
|
||||
return i.to_bytes(1, byteorder='little')
|
||||
# variable integer
|
||||
|
||||
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))
|
||||
|
||||
|
||||
# generic big endian MPI format
|
||||
def bn_bytes(v, have_ext=False):
|
||||
@ -627,12 +828,10 @@ def bn2mpi(v):
|
||||
have_ext = False
|
||||
if v.bit_length() > 0:
|
||||
have_ext = (v.bit_length() & 0x07) == 0
|
||||
|
||||
neg = False
|
||||
if v < 0:
|
||||
neg = True
|
||||
v = -v
|
||||
|
||||
s = struct.pack(b">I", bn_bytes(v, have_ext))
|
||||
ext = bytearray()
|
||||
if have_ext:
|
||||
@ -655,7 +854,6 @@ def mpi2bn(s):
|
||||
return None
|
||||
if v_len == 0:
|
||||
return 0
|
||||
|
||||
v_str = bytearray(s[4:])
|
||||
neg = False
|
||||
i = v_str[0]
|
||||
@ -663,7 +861,6 @@ def mpi2bn(s):
|
||||
neg = True
|
||||
i &= ~0x80
|
||||
v_str[0] = i
|
||||
|
||||
v = bin2bn(v_str)
|
||||
|
||||
if neg:
|
||||
@ -701,6 +898,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
|
||||
|
||||
|
||||
313
pybtc/transaction.py
Normal file
313
pybtc/transaction.py
Normal file
@ -0,0 +1,313 @@
|
||||
|
||||
from struct import unpack
|
||||
import json
|
||||
from .tools import *
|
||||
from .address import PrivateKey
|
||||
from binascii import hexlify, unhexlify
|
||||
|
||||
|
||||
class Transaction(dict):
|
||||
def __init__(self, raw_tx=None):
|
||||
self["format"] = "raw"
|
||||
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"] = False
|
||||
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))[0]
|
||||
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))[0]
|
||||
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))[0]
|
||||
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
|
||||
else:
|
||||
self["coinbase"] = False
|
||||
if sw:
|
||||
self["segwit"] = True
|
||||
self["hash"] = double_sha256(b)
|
||||
self["txId"] = double_sha256(b[:4] + b[6:sw] + b[-4:])
|
||||
else:
|
||||
self["segwit"] = False
|
||||
self["txId"] = double_sha256(b)
|
||||
self["hash"] = self["txId"]
|
||||
|
||||
def decode(self, testnet = False):
|
||||
self["format"] = "decoded"
|
||||
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 self["segwit"]:
|
||||
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 self["segwit"]:
|
||||
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
|
||||
return json.dumps(self.decode())
|
||||
|
||||
# def add_input(self, tx_id=None, v_out=0, sequence=0xffffffff,
|
||||
# script_sig=b"", tx_in_witness=None, amount=None,
|
||||
# script_pub_key=None, private_key=None):
|
||||
#
|
||||
# if type(tx_id) == Input:
|
||||
#
|
||||
# else:
|
||||
# i = Input(tx_id, )
|
||||
# if self["vIn"]:
|
||||
# # coinbase tx only one input allowed
|
||||
# assert tx_id != None
|
||||
# if tx_id is None:
|
||||
# tx_id = b"\x00" * 32
|
||||
# assert v_out == 0 and sequence == 0xffffffff
|
||||
#
|
||||
# if type(tx_id) == str:
|
||||
# tx_id = unhexlify(tx_id)
|
||||
# else:
|
||||
# assert type(script_sig) == bytes
|
||||
# assert len(tx_id) == 32
|
||||
# assert type(v_out) == int
|
||||
# assert v_out <= 0xffffffff and v_out >= 0
|
||||
# assert type(sequence) == int
|
||||
# assert sequence <= 0xffffffff and sequence >= 0
|
||||
# if type(script_sig) == str:
|
||||
# script_sig = unhexlify(script_sig)
|
||||
# else:
|
||||
# assert type(script_sig) == bytes
|
||||
# assert len(script_sig) <= 520
|
||||
# if private_key:
|
||||
# if type(private_key) != PrivateKey:
|
||||
# private_key = PrivateKey(private_key)
|
||||
# if amount:
|
||||
# assert type(amount) == int
|
||||
# assert amount >= 0 and amount <= MAX_AMOUNT
|
||||
# if tx_in_witness:
|
||||
# assert type(tx_in_witness) == list
|
||||
# l = 0
|
||||
# witness = []
|
||||
# for w in tx_in_witness:
|
||||
# if type(w) == str:
|
||||
# witness.append(unhexlify(w) if self["format"] == "raw" else w)
|
||||
# else:
|
||||
# witness.append(w if self["format"] == "raw" else unhexlify(w))
|
||||
# l += 1 + len(w)
|
||||
# if len(w) >= 0x4c:
|
||||
# l += 1
|
||||
# if len(w) > 0xff:
|
||||
# l += 1
|
||||
# # witness script limit
|
||||
# assert l <= 10000
|
||||
# if tx_id == b"\x00" * 32:
|
||||
# assert v_out == 0 and sequence == 0xffffffff and len(script_sig) <= 100
|
||||
# self["coinbase"] = True
|
||||
#
|
||||
# k = len(self["vIn"])
|
||||
# self["vIn"][k] = dict()
|
||||
# self["vIn"][k]["vOut"] = v_out
|
||||
# self["vIn"][k]["sequence"] = sequence
|
||||
# if self["format"] == "raw":
|
||||
# self["vIn"][k]["txId"] = tx_id
|
||||
# self["vIn"][k]["scriptSig"] = script_sig
|
||||
# if tx_in_witness:
|
||||
# self["segwit"] = True
|
||||
# self["vIn"][k]["txInWitness"] = witness
|
||||
# else:
|
||||
# self["vIn"][k]["txId"] = rh2s(tx_id)
|
||||
# self["vIn"][k]["scriptSig"] = script_sig
|
||||
# self["vIn"][i]["scriptSigOpcodes"] = decode_script(script_sig)
|
||||
# self["vIn"][i]["scriptSigAsm"] = decode_script(script_sig, 1)
|
||||
# if tx_in_witness:
|
||||
# self["segwit"] = True
|
||||
# self["vIn"][k]["txInWitness"] = witness
|
||||
# if amount:
|
||||
# self["value"] = amount
|
||||
# if private_key:
|
||||
# self["privateKey"] = private_key
|
||||
#
|
||||
# # todo
|
||||
# # if self["vOut"]:
|
||||
# # self.__refresh_tx__()
|
||||
#
|
||||
# """
|
||||
# написать сценарии использования
|
||||
# """
|
||||
@ -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,83 +14,95 @@ 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)
|
||||
self.assertEqual(tools.is_WIF_valid("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf"),1)
|
||||
self.assertEqual(tools.is_WIF_valid("5KPPLXhtga99qqMcWRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf"),0)
|
||||
self.assertEqual(tools.is_WIF_valid("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L"),1)
|
||||
self.assertEqual(tools.is_WIF_valid("cUWo47XLYiyFByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6"),1)
|
||||
self.assertEqual(tools.is_WIF_valid("cUWo47XLYiyByuFicFS3y4FAza3r3R5XA7Bm7wA3dgSKDYox7h6"),0)
|
||||
self.assertEqual(tools.is_wif_valid("L49obCXV7fGz2YRzLCSJgeZBYmGeBbKPT7xiehUeYX2S4URkPFZX"), 1)
|
||||
self.assertEqual(tools.is_wif_valid("5KPPLXhtga99qqMceRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf"), 1)
|
||||
self.assertEqual(tools.is_wif_valid("5KPPLXhtga99qqMcWRo4Z6LXV3Kx6a9hRx3ez2U7EwP5KZfy2Wf"), 0)
|
||||
self.assertEqual(tools.is_wif_valid("93A1vGXSGoDHotruGmgyRgtV8hgfFjgtmtuc4epcag886W9d44L"), 1)
|
||||
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)
|
||||
|
||||
|
||||
1165
tests/test/block.py
1165
tests/test/block.py
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 *
|
||||
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,198 @@
|
||||
import unittest
|
||||
from pybtc import blockchain
|
||||
import os
|
||||
import 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)
|
||||
stream.seek(80)
|
||||
return {i: Transaction(stream) for i in range(var_int_to_int(read_var_int(stream)))}
|
||||
|
||||
|
||||
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"
|
||||
non_segwit_view = "020000000140d43a99926d43eb0e619bf0b3d83b4a31f60c176beecfb9d35bf45e54d0f7420" \
|
||||
"100000017160014a4b4ca48de0b3fffc15404a1acdc8dbaae226955ffffffff0100e1f50500" \
|
||||
"00000017a9144a1154d50b03292b3024370901711946cb7cccc38700000000"
|
||||
segwit_view = "0200000000010140d43a99926d43eb0e619bf0b3d83b4a31f60c176beecfb9d35bf45e54d0f7420" \
|
||||
"00000017160014a4b4ca48de0b3fffc15404a1acdc8dbaae226955ffffffff0100e1f5050000000" \
|
||||
"017a9144a1154d50b03292b3024370901711946cb7cccc387024830450221008604ef8f6d8afa89" \
|
||||
"2dee0f31259b6ce02dd70c545cfcfed8148179971876c54a022076d771d6e91bed212783c9b06e0" \
|
||||
"de600fab2d518fad6f15a2b191d7fbd262a3e0121039d25ab79f41f75ceaf882411fd41fa670a4c" \
|
||||
"672c23ffaf0e361a969cde0692e800000000"
|
||||
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"
|
||||
non_segwit_view = "01000000060c02c24bbfefd94cdc4f58a3f83f93e05b14ad968ec6aba54190c3dcba6eef1b00" \
|
||||
"000000da00483045022100f4dbf2ca7b5da97bd78818635d48004e6bf1a6f7e5e24bcecb7d93" \
|
||||
"f554e49eaf02200a05025d93475b6372d14bd8fe8366fe10570ade772b19d124d3b0175b9f6e" \
|
||||
"da0147304402202290feb53fc4cb077c5d3eed0ed5367fef4011ac708c1acaaa5003e4ed680d" \
|
||||
"df022012c52160ae6b85fc59ceed80c7cacd5358b80712371733de7c76fef552114ee6014752" \
|
||||
"2103ee30ea502d692ecfc79dfcb6fb2d6914fc70ba80db971beebacccdbaed40d7c52102f52d" \
|
||||
"b885d04dc43ca8562471759dd621b899faf508caba70963d9228bfd2415e52ae00000000dab0" \
|
||||
"20ee0a80a818e4d20a52aa7ba367a0a2d430d22c26ccb4572527e259e14a01000000d9004730" \
|
||||
"44022064745ac8cae859bb19305a550981b8d39b69efec55b9a423dca645cd3b5c845502205c" \
|
||||
"f375839d7f056235feb550a8138a03e75fa140503a2ce61fe239a3bfe4214501473044022072" \
|
||||
"8b0393d5427d8abb56a608c6b1a0b14c5455f3abeb56ce8a5c7f70035af71d022052a99e4e38" \
|
||||
"9790b364f6180caf1523d6da2b3daabe85952705023be2b5409b360147522103e296937dbdaf" \
|
||||
"dae4d0a45b33d9a691b0c0e71d97bd2ffc82da895a251f74bd7e2103ead7ad0c398f928cbe85" \
|
||||
"1a6b387a5e74d139487caf4d4ac3dc3d478254dbbb4452ae0000000067a6c2e2f14fc412b3f5" \
|
||||
"627fafac2fe43009bc403ec680839579444df2ce042b00000000da00483045022100d3bdc055" \
|
||||
"fa5dcce335a1d572b1c3ccb8cc9ba91960c6361c77e29ded716e233102200e7ebb43fd39fb98" \
|
||||
"c714098d4fda32d94cdbefdd96c0c918b788aacc6164953c0147304402202f4338d2710edb19" \
|
||||
"60dcf7136411f065a16bee4e44b86604d64c660315bc55040220238c1c3216feb31051f77982" \
|
||||
"97317819da1dfa830d24a6a9e38a37367a68ebd101475221037b2987df626510ce25e6ce5fdb" \
|
||||
"716705e23fecb7398b2cbb0a1c0af7ca5da717210345e358653b4580b5bd68d263089a0a2bf9" \
|
||||
"fcc1e145fcf2a3d4b9ab5cd7e1a76752ae000000004f28d63103dfb86a5d92d2daf328bbb35d" \
|
||||
"72239766a5853b7076a90d1745813200000000da00483045022100e89ac8215ee87186de284c" \
|
||||
"419b2522ebfb2ecb8063d0f91942f2ad63f383d3d4022036485902bb1f2e0b2cc645aab8781d" \
|
||||
"ef27f25e91d8256d48dd48d5cfca1a21c20147304402201449379f1d57f2b7ad1dc0882f5962" \
|
||||
"7287a6c32180ffa7637941b0eaa666dd4b022028eb0eed77e1b92de046098c855834a5feeade" \
|
||||
"a55d17160bc6d11d47184e8b51014752210283db605dc305201ab9be509a22d2c83b388002fb" \
|
||||
"54ecd82d86efe83c0a1d35822103146f745eff0ae31fe899aafd27d51d2c0f5b0c03f2f47b3c" \
|
||||
"65bb26ec7581ad8652ae0000000021cb3b00d1f22455e76e86872e00ef556578bcc112071e6a" \
|
||||
"5b4ac02ab682fdb301000000232200206ea344e9a4a8f8a8983479af2ae3ed29fab153955af1" \
|
||||
"4457780a304a6832b9c50000000016dcc4b40a514c43ed61d6c01a9006d7f21a6d30b99b3e58" \
|
||||
"0d21578e35002502000000002322002049ea1f7c280b32fee0dce2e1801df2218df59d64614c" \
|
||||
"4fe76c043ee2c80116700000000002005ed0b20000000017a91495c5c19257aa52bd4b702ba1" \
|
||||
"a5e29b8d72a75a3a876d6b4e010000000017a91487b6255a5df746188f0bd22ed0194a40ec98" \
|
||||
"f2de87be810700"
|
||||
segwit_view = "010000000001060c02c24bbfefd94cdc4f58a3f83f93e05b14ad968ec6aba54190c3dcba6eef1b00" \
|
||||
"000000da00483045022100f4dbf2ca7b5da97bd78818635d48004e6bf1a6f7e5e24bcecb7d93f554" \
|
||||
"e49eaf02200a05025d93475b6372d14bd8fe8366fe10570ade772b19d124d3b0175b9f6eda014730" \
|
||||
"4402202290feb53fc4cb077c5d3eed0ed5367fef4011ac708c1acaaa5003e4ed680ddf022012c521" \
|
||||
"60ae6b85fc59ceed80c7cacd5358b80712371733de7c76fef552114ee60147522103ee30ea502d69" \
|
||||
"2ecfc79dfcb6fb2d6914fc70ba80db971beebacccdbaed40d7c52102f52db885d04dc43ca8562471" \
|
||||
"759dd621b899faf508caba70963d9228bfd2415e52ae00000000dab020ee0a80a818e4d20a52aa7b" \
|
||||
"a367a0a2d430d22c26ccb4572527e259e14a01000000d900473044022064745ac8cae859bb19305a" \
|
||||
"550981b8d39b69efec55b9a423dca645cd3b5c845502205cf375839d7f056235feb550a8138a03e7" \
|
||||
"5fa140503a2ce61fe239a3bfe42145014730440220728b0393d5427d8abb56a608c6b1a0b14c5455" \
|
||||
"f3abeb56ce8a5c7f70035af71d022052a99e4e389790b364f6180caf1523d6da2b3daabe85952705" \
|
||||
"023be2b5409b360147522103e296937dbdafdae4d0a45b33d9a691b0c0e71d97bd2ffc82da895a25" \
|
||||
"1f74bd7e2103ead7ad0c398f928cbe851a6b387a5e74d139487caf4d4ac3dc3d478254dbbb4452ae" \
|
||||
"0000000067a6c2e2f14fc412b3f5627fafac2fe43009bc403ec680839579444df2ce042b00000000" \
|
||||
"da00483045022100d3bdc055fa5dcce335a1d572b1c3ccb8cc9ba91960c6361c77e29ded716e2331" \
|
||||
"02200e7ebb43fd39fb98c714098d4fda32d94cdbefdd96c0c918b788aacc6164953c014730440220" \
|
||||
"2f4338d2710edb1960dcf7136411f065a16bee4e44b86604d64c660315bc55040220238c1c3216fe" \
|
||||
"b31051f7798297317819da1dfa830d24a6a9e38a37367a68ebd101475221037b2987df626510ce25" \
|
||||
"e6ce5fdb716705e23fecb7398b2cbb0a1c0af7ca5da717210345e358653b4580b5bd68d263089a0a" \
|
||||
"2bf9fcc1e145fcf2a3d4b9ab5cd7e1a76752ae000000004f28d63103dfb86a5d92d2daf328bbb35d" \
|
||||
"72239766a5853b7076a90d1745813200000000da00483045022100e89ac8215ee87186de284c419b" \
|
||||
"2522ebfb2ecb8063d0f91942f2ad63f383d3d4022036485902bb1f2e0b2cc645aab8781def27f25e" \
|
||||
"91d8256d48dd48d5cfca1a21c20147304402201449379f1d57f2b7ad1dc0882f59627287a6c32180" \
|
||||
"ffa7637941b0eaa666dd4b022028eb0eed77e1b92de046098c855834a5feeadea55d17160bc6d11d" \
|
||||
"47184e8b51014752210283db605dc305201ab9be509a22d2c83b388002fb54ecd82d86efe83c0a1d" \
|
||||
"35822103146f745eff0ae31fe899aafd27d51d2c0f5b0c03f2f47b3c65bb26ec7581ad8652ae0000" \
|
||||
"000021cb3b00d1f22455e76e86872e00ef556578bcc112071e6a5b4ac02ab682fdb3010000002322" \
|
||||
"00206ea344e9a4a8f8a8983479af2ae3ed29fab153955af14457780a304a6832b9c50000000016dc" \
|
||||
"c4b40a514c43ed61d6c01a9006d7f21a6d30b99b3e580d21578e35002502000000002322002049ea" \
|
||||
"1f7c280b32fee0dce2e1801df2218df59d64614c4fe76c043ee2c80116700000000002005ed0b200" \
|
||||
"00000017a91495c5c19257aa52bd4b702ba1a5e29b8d72a75a3a876d6b4e010000000017a91487b6" \
|
||||
"255a5df746188f0bd22ed0194a40ec98f2de87000000000400473044022100d0d2ded141c9369bcc" \
|
||||
"99de23d3d41d1d99d6cff47126df1b0c4d4797f947eacf021f790f1c112b3425ebc3251d719aae6e" \
|
||||
"f0f9830b688585275591a5353f1f973801483045022100bf06c762e6ab64258d2f2777a66fe32ddd" \
|
||||
"8f36e232b80bf5afa6ff9b9aa73ee0022049caf991fce808e60a9b17499f5e0dc11f6163e3ef7bca" \
|
||||
"8109b72b5695d674210147522103edd556806048b319d71f43466c4415001bb32d8afe3aac06532d" \
|
||||
"3ac210fd0e86210215e16727cf1389b4ee377487385f3ec595841a6bb747eb9c3a5cd559e9b1c8dc" \
|
||||
"52ae040047304402204e9cc87526e148d236d692fa70104d26b8df632f30f4e3be38a2e99cec76d0" \
|
||||
"f80220354ae575c3537c0ad2399a6037a9164b0cb147b12f262efc906649ca7950e2eb0147304402" \
|
||||
"203553bcd1565804ec71c997c87006bd91c639b74a004b19a239c7f551aab5635a0220753f74e065" \
|
||||
"c0b7cdf67d16b00f6a20dda7159a49f20aa493a7889b2851b2fea30147522103b09ac1fa65a55fa4" \
|
||||
"feadea57c4cf417d7490065d8b844ada60c242a441e0e3a42103c0625169b46dbbde3492db7c62f1" \
|
||||
"be8f582131467620cef17335306bad7ef88a52aebe810700"
|
||||
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)
|
||||
|
||||
tx = "01000000014cee27ba570d2cca50bb9b3f7374c7eb24ec16ffec0a077c84c1cc23b0161804010000008b48304" \
|
||||
"502200f1100f78596c8d46fb2f39c570ce6945956a3dd33c48fbdbe53af1c383182ed022100a85b528ea21ee7" \
|
||||
"f39b2ec1568ac19f26f4dd4fb9d3dbf70587986de3c2c90fa801410426e4d0890ad5272b2b9a10ca3f518f7e0" \
|
||||
"25932caa62f13467e444df89ed25f24f4fc5075cad32f468c8f7f913e30057449d65623726e7102f5eaa326d4" \
|
||||
"86ebf7ffffffff020010000000000000006020e908000000001976a914947236437233a71cb033a53932008db" \
|
||||
"fe346388e88ac00000000"
|
||||
Transaction(tx)
|
||||
tx = "01000000011e6c87805dad469ed72b42668b858df90e6b007c6410a7bde65bb1cf687d8409000000006b48304" \
|
||||
"502204f3353cf129bb805fb90315aeb6d5ab8e0937129c4b0f1422495e42b6bf0e928022100cbdd2811a4c943" \
|
||||
"97aa731c224ee0c7290fea6bc17a9b3ce5957d9937c60f4f97012103e2a0e6a91fa985ce4dda7f048fca5ec82" \
|
||||
"64292aed9290594321aa53d37fdea32ffffffff0160e3160000000000fdaf0563ff054effffffff4da3054672" \
|
||||
"6f6d2061336136316665663433333039623966623233323235646637393130623033616663353436356239204" \
|
||||
"d6f6e205365702031372030303a30303a303020323030310a46726f6d3a205361746f736869204e616b616d6f" \
|
||||
"746f203c7361746f7368696e40676d782e636f6d3e0a446174653a204d6f6e2c2031322041756720323031332" \
|
||||
"030323a32383a3032202d303230300a5375626a6563743a205b50415443485d2052656d6f7665202853494e47" \
|
||||
"4c457c444f55424c4529425954450a0a492072656d6f76656420746869732066726f6d20426974636f696e206" \
|
||||
"96e20663165316662346264656638373863386663313536346661343138643434653735343161376538330a69" \
|
||||
"6e2053657074203720323031302c20616c6d6f73742074687265652079656172732061676f2e2042652077617" \
|
||||
"26e6564207468617420492068617665206e6f740a61637475616c6c7920746573746564207468697320706174" \
|
||||
"63682e0a2d2d2d0a206261636b656e64732f626974636f696e642f646573657269616c697a652e7079207c202" \
|
||||
"0202038202b2d2d2d2d2d2d2d0a20312066696c65206368616e6765642c203120696e73657274696f6e282b29" \
|
||||
"2c20372064656c6574696f6e73282d290a0a64696666202d2d67697420612f6261636b656e64732f626974636" \
|
||||
"f696e642f646573657269616c697a652e707920622f6261636b656e64732f626974636f696e642f6465736572" \
|
||||
"69616c697a652e70790a696e64657820363632303538332e2e38396239623162203130303634340a2d2d2d206" \
|
||||
"12f6261636b656e64732f626974636f696e642f646573657269616c697a652e70790a2b2b2b20622f6261636b" \
|
||||
"656e64732f626974636f696e642f646573657269616c697a652e70790a4040202d3238302c3130202b3238302" \
|
||||
"c38204040206f70636f646573203d20456e756d65726174696f6e28224f70636f646573222c205b0a20202020" \
|
||||
"20224f505f57495448494e222c20224f505f524950454d44313630222c20224f505f53484131222c20224f505" \
|
||||
"f534841323536222c20224f505f48415348313630222c0a2020202020224f505f48415348323536222c20224f" \
|
||||
"505f434f4445534550415241544f52222c20224f505f434845434b534947222c20224f505f434845434b53494" \
|
||||
"7564552494659222c20224f505f434845434b4d554c5449534947222c0a2020202020224f505f434845434b4d" \
|
||||
"554c5449534947564552494659222c0a2d2020202028224f505f53494e474c45425954455f454e44222c20307" \
|
||||
"84630292c0a2d2020202028224f505f444f55424c45425954455f424547494e222c20307846303030292c0a20" \
|
||||
"20202020224f505f5055424b4559222c20224f505f5055424b455948415348222c0a2d2020202028224f505f4" \
|
||||
"94e56414c49444f50434f4445222c20307846464646292c0a2b2020202028224f505f494e56414c49444f5043" \
|
||||
"4f4445222c2030784646292c0a205d290a200a200a4040202d3239332c3130202b3239312c362040402064656" \
|
||||
"6207363726970745f4765744f70286279746573293a0a202020202020202020766368203d204e6f6e650a2020" \
|
||||
"202020202020206f70636f6465203d206f72642862797465735b695d290a20202020202020202069202b3d203" \
|
||||
"10a2d20202020202020206966206f70636f6465203e3d206f70636f6465732e4f505f53494e474c4542595445" \
|
||||
"5f454e4420616e642069203c206c656e286279746573293a0a2d2020202020202020202020206f70636f64652" \
|
||||
"03c3c3d20380a2d2020202020202020202020206f70636f6465207c3d206f72642862797465735b695d290a2d" \
|
||||
"20202020202020202020202069202b3d20310a200a2020202020202020206966206f70636f6465203c3d206f7" \
|
||||
"0636f6465732e4f505f5055534844415441343a0a202020202020202020202020206e53697a65203d206f7063" \
|
||||
"6f64650a2d2d200a312e372e392e340a0a6800000000"
|
||||
Transaction(tx)
|
||||
tx = "0100000001c86c4ddc01f59b748e6a55a6d09c5bce7574fbdec721ca468768b5d6d9e3fb00000000006b48304" \
|
||||
"5022076b5504ad7aff614e32159ac055362a1197c9a5e50de48cf4f05c7547b39c0b5022100ea67efb2585aae" \
|
||||
"40a53363f48e3e38dfc7387b238f8716fa53a5f0ed51b7c314012102452928340bc618777d217a52f30d8e144" \
|
||||
"0d98f561c523a31834a1614106f3c15ffffffff025cf5352f0d0000001976a9141855d5890b8aec536ffc3e59" \
|
||||
"cb586e98b34b5b9288ac0bd32204000000001976a9146f3f6845da01e856a426c31dfeef188c06bf574d88ac0" \
|
||||
"0000000"
|
||||
Transaction(tx)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user