connector

This commit is contained in:
4tochka 2019-05-06 17:48:48 +04:00
parent 52db561690
commit fbbf099dbc
8 changed files with 90 additions and 34 deletions

View File

@ -51,11 +51,23 @@ static PyObject* crypto_double_sha256(PyObject *, PyObject* args) {
return return_value; return return_value;
} }
static PyObject* crypto_sha256(PyObject *, PyObject* args) {
Py_buffer buffer;
if (!PyArg_ParseTuple(args,"y*", &buffer)) return NULL;
unsigned char h[CSHA256::OUTPUT_SIZE];
CSHA256().Write((const unsigned char*)buffer.buf, buffer.len).Finalize(h);
PyBuffer_Release(&buffer);
PyObject *return_value = Py_BuildValue("y#", h, CSHA256::OUTPUT_SIZE);
Py_DECREF(h);
return return_value;
}
static PyMethodDef module_methods[] = { static PyMethodDef module_methods[] = {
{ "__decode_base58__", (PyCFunction)crypto_decode_base58, METH_VARARGS, nullptr }, { "__decode_base58__", (PyCFunction)crypto_decode_base58, METH_VARARGS, nullptr },
{ "__encode_base58__", (PyCFunction)crypto_encode_base58, METH_VARARGS, nullptr }, { "__encode_base58__", (PyCFunction)crypto_encode_base58, METH_VARARGS, nullptr },
{ "__double_sha256__", (PyCFunction)crypto_double_sha256, METH_VARARGS, nullptr }, { "__double_sha256__", (PyCFunction)crypto_double_sha256, METH_VARARGS, nullptr },
{ "__sha256__", (PyCFunction)crypto_sha256, METH_VARARGS, nullptr },
{ nullptr, nullptr, 0, nullptr } { nullptr, nullptr, 0, nullptr }
}; };

View File

@ -7,7 +7,7 @@ from pybtc.transaction import Transaction
class Block(dict): class Block(dict):
def __init__(self, raw_block=None, format="decoded", version=536870912, testnet=False): def __init__(self, raw_block=None, format="decoded", version=536870912, testnet=False, keep_raw_tx=False):
if format not in ("decoded", "raw"): if format not in ("decoded", "raw"):
raise ValueError("tx_format error, raw or decoded allowed") raise ValueError("tx_format error, raw or decoded allowed")
self["format"] = format self["format"] = format
@ -52,7 +52,7 @@ class Block(dict):
block_target = int.from_bytes(self["hash"], byteorder="little") block_target = int.from_bytes(self["hash"], byteorder="little")
self["difficulty"] = target_to_difficulty(block_target) self["difficulty"] = target_to_difficulty(block_target)
tx_count = var_int_to_int(read_var_int(s)) tx_count = var_int_to_int(read_var_int(s))
self["tx"] = {i: Transaction(s, format="raw") self["tx"] = {i: Transaction(s, format="raw", keep_raw_tx=keep_raw_tx)
for i in range(tx_count)} for i in range(tx_count)}
for t in self["tx"].values(): for t in self["tx"].values():
self["amount"] += t["amount"] self["amount"] += t["amount"]

View File

@ -12,6 +12,9 @@ def __encode_base58__(h):
def __double_sha256__(h): def __double_sha256__(h):
return _crypto.__double_sha256__(h) return _crypto.__double_sha256__(h)
def __sha256__(h):
return _crypto.__sha256__(h)
def __secp256k1_context_randomize__(seed = None): def __secp256k1_context_randomize__(seed = None):
if seed is None: if seed is None:

View File

@ -2,6 +2,7 @@ from hashlib import new as hashlib_new
from hashlib import sha256 as hashlib_sha256 from hashlib import sha256 as hashlib_sha256
from hashlib import sha512 as hashlib_sha512 from hashlib import sha512 as hashlib_sha512
from pybtc.crypto import __double_sha256__ from pybtc.crypto import __double_sha256__
from pybtc.crypto import __sha256__
import hmac import hmac
bytes_from_hex = bytes.fromhex bytes_from_hex = bytes.fromhex
@ -9,7 +10,8 @@ bytes_from_hex = bytes.fromhex
def sha256(h, hex=False): def sha256(h, hex=False):
if isinstance(h, str): if isinstance(h, str):
h = bytes_from_hex(h) h = bytes_from_hex(h)
return hashlib_sha256(h).hexdigest() if hex else hashlib_sha256(h).digest() # return hashlib_sha256(h).hexdigest() if hex else hashlib_sha256(h).digest()
return __sha256__(h).hex() if hex else __sha256__(h)
def double_sha256(h, hex=False): def double_sha256(h, hex=False):
@ -18,6 +20,7 @@ def double_sha256(h, hex=False):
h = bytes_from_hex(h) h = bytes_from_hex(h)
# if isinstance(h, bytearray): # if isinstance(h, bytearray):
# h = bytes(h) # h = bytes(h)
# return hashlib_sha256(hashlib_sha256(h).digest()).digest()
return __double_sha256__(h).hex() if hex else __double_sha256__(h) return __double_sha256__(h).hex() if hex else __double_sha256__(h)

View File

@ -38,8 +38,7 @@ def parse_script(script, segwit=True):
try: try:
script = bytes_from_hex(script) script = bytes_from_hex(script)
except: except:
pass raise ValueError("hex encoded string required")
assert isinstance(script, bytes)
l = len(script) l = len(script)
if segwit: if segwit:
if l == 22 and script[0] == 0: if l == 22 and script[0] == 0:

View File

@ -148,9 +148,16 @@ def read_var_int(stream):
:param stream: io.BytesIO stream. :param stream: io.BytesIO stream.
:return: bytes. :return: bytes.
""" """
read = stream.read l = stream.read(1)
l = read(1) if l[0] == 253:
return b"".join((l, read(get_var_int_len(l) - 1))) s = 3
elif l[0] == 254:
s = 5
elif l[0] == 255:
s = 9
else:
return l
return b"".join((l, stream.read(s - 1)))
def read_var_list(stream, data_type): def read_var_list(stream, data_type):

View File

@ -601,7 +601,7 @@ class BlockDeserializeTests(unittest.TestCase):
fc = f.readline() fc = f.readline()
qt = time.time() qt = time.time()
bt = ( bt = (
Block(fc[:-1], format="raw"), Block(fc[:-1], format="raw", keep_raw_tx=False),
) )
print("decoded block", time.time() - qt ) print("decoded block", time.time() - qt )
import pickle import pickle
@ -613,10 +613,10 @@ class BlockDeserializeTests(unittest.TestCase):
print("decoded block load", time.time() - qt) print("decoded block load", time.time() - qt)
import cProfile import cProfile
# cProfile.run("import pybtc;" cProfile.run("import pybtc;"
# "f = open('./pybtc/test/raw_block.txt');" "f = open('./pybtc/test/raw_block.txt');"
# "fc = f.readline();" "fc = f.readline();"
# "pybtc.Block(fc[:-1], format='decoded')") "pybtc.Block(fc[:-1], format='raw', keep_raw_tx=False)")
# cProfile.run("import pybtc;" # cProfile.run("import pybtc;"
# "f = open('./pybtc/test/raw_block.txt');" # "f = open('./pybtc/test/raw_block.txt');"
# "fc = f.readline();" # "fc = f.readline();"

View File

@ -35,7 +35,8 @@ class Transaction(dict):
:param boolean testnet: address type for "decoded" transaction representation. :param boolean testnet: address type for "decoded" transaction representation.
""" """
def __init__(self, raw_tx=None, format="decoded", version=1, lock_time=0, testnet=False, auto_commit=True): def __init__(self, raw_tx=None, format="decoded", version=1,
lock_time=0, testnet=False, auto_commit=True, keep_raw_tx=False):
if format not in ("decoded", "raw"): if format not in ("decoded", "raw"):
raise ValueError("format error, raw or decoded allowed") raise ValueError("format error, raw or decoded allowed")
self.auto_commit = auto_commit self.auto_commit = auto_commit
@ -64,6 +65,8 @@ class Transaction(dict):
if raw_tx is None: if raw_tx is None:
return return
self["rawTx"] = []
rtx = self["rawTx"].append
self["amount"] = 0 self["amount"] = 0
sw = sw_len = 0 sw = sw_len = 0
stream = self.get_stream(raw_tx) stream = self.get_stream(raw_tx)
@ -72,30 +75,48 @@ class Transaction(dict):
tell = stream.tell tell = stream.tell
seek = stream.seek seek = stream.seek
# start deserialization # start deserialization
self["version"] = unpack('<L', read(4))[0] t = read(4)
rtx(t)
self["version"] = unpack('<L', t)[0]
n = read_var_int(stream) n = read_var_int(stream)
rtx(n)
if n == b'\x00': if n == b'\x00':
# segwit format # segwit format
sw = 1 sw = 1
self["flag"] = read(1) self["flag"] = read(1)
rtx(self["flag"])
n = read_var_int(stream) n = read_var_int(stream)
rtx(n)
# inputs # inputs
ic = var_int_to_int(n) ic = var_int_to_int(n)
for k in range(ic): for k in range(ic):
self["vIn"][k] = dict() self["vIn"][k] = dict()
self["vIn"][k]["txId"] = read(32) self["vIn"][k]["txId"] = read(32)
self["vIn"][k]["vOut"] = unpack('<L', read(4))[0] rtx(self["vIn"][k]["txId"])
self["vIn"][k]["scriptSig"] = read(var_int_to_int(read_var_int(stream))) t = read(4)
self["vIn"][k]["sequence"] = unpack('<L', read(4))[0] rtx(t)
self["vIn"][k]["vOut"] = unpack('<L', t)[0]
t = read_var_int(stream)
rtx(t)
self["vIn"][k]["scriptSig"] = read(var_int_to_int(t))
rtx(self["vIn"][k]["scriptSig"])
t = read(4)
rtx(t)
self["vIn"][k]["sequence"] = unpack('<L', t)[0]
# outputs # outputs
for k in range(var_int_to_int(read_var_int(stream))): t = read_var_int(stream)
rtx(t)
for k in range(var_int_to_int(t)):
self["vOut"][k] = dict() self["vOut"][k] = dict()
self["vOut"][k]["value"] = unpack('<Q', read(8))[0] t = read(8)
self["vOut"][k]["value"] = unpack('<Q', t)[0]
rtx(t)
self["amount"] += self["vOut"][k]["value"] self["amount"] += self["vOut"][k]["value"]
self["vOut"][k]["scriptPubKey"] = read(var_int_to_int(read_var_int(stream))) t = read_var_int(stream)
self["vOut"][k]["scriptPubKey"] = read(var_int_to_int(t))
rtx(t)
rtx(self["vOut"][k]["scriptPubKey"])
s = parse_script(self["vOut"][k]["scriptPubKey"]) s = parse_script(self["vOut"][k]["scriptPubKey"])
self["vOut"][k]["nType"] = s["nType"] self["vOut"][k]["nType"] = s["nType"]
self["vOut"][k]["type"] = s["type"] self["vOut"][k]["type"] = s["type"]
@ -110,16 +131,23 @@ class Transaction(dict):
if sw: if sw:
sw = tell() - start sw = tell() - start
for k in range(ic): for k in range(ic):
self["vIn"][k]["txInWitness"] = [read(var_int_to_int(read_var_int(stream))) \ self["vIn"][k]["txInWitness"] = []
for c in range(var_int_to_int(read_var_int(stream)))] t = read_var_int(stream)
sw_len = (stream.tell() - start) - sw + 2 rtx(t)
for c in range(var_int_to_int(t)):
l = read_var_int(stream)
rtx(l)
d = read(var_int_to_int(l))
rtx(d)
self["vIn"][k]["txInWitness"].append(d)
self["lockTime"] = unpack('<L', read(4))[0] sw_len = (stream.tell() - start) - sw + 2
t = read(4)
rtx(t)
self["lockTime"] = unpack('<L', t)[0]
end = tell() end = tell()
seek(start) self["rawTx"] = b"".join(self["rawTx"])
b = read(end - start)
self["rawTx"] = b
self["size"] = end - start self["size"] = end - start
self["bSize"] = end - start - sw_len self["bSize"] = end - start - sw_len
self["weight"] = self["bSize"] * 3 + self["size"] self["weight"] = self["bSize"] * 3 + self["size"]
@ -132,12 +160,16 @@ class Transaction(dict):
self["coinbase"] = False self["coinbase"] = False
if sw: if sw:
self["segwit"] = True self["segwit"] = True
self["hash"] = double_sha256(b) self["hash"] = double_sha256(self["rawTx"])
self["txId"] = double_sha256(b"%s%s%s" % (b[:4], b[6:sw],b[-4:])) self["txId"] = double_sha256(b"".join((self["rawTx"][:4], self["rawTx"][6:sw], self["rawTx"][-4:])))
else: else:
self["segwit"] = False self["segwit"] = False
self["txId"] = double_sha256(b) self["txId"] = double_sha256(self["rawTx"])
self["hash"] = self["txId"] self["hash"] = self["txId"]
if not keep_raw_tx:
self["rawTx"] = None
else:
self["rawTx"] = None
if self["format"] == "decoded": if self["format"] == "decoded":
self.decode() self.decode()