From fbbf099dbc93d83597c32584a201963319b1b0fc Mon Sep 17 00:00:00 2001 From: 4tochka Date: Mon, 6 May 2019 17:48:48 +0400 Subject: [PATCH] connector --- pybtc/_crypto/module_crypto.cpp | 12 ++++++ pybtc/block.py | 4 +- pybtc/crypto.py | 3 ++ pybtc/functions/hash.py | 5 ++- pybtc/functions/script.py | 3 +- pybtc/functions/tools.py | 13 ++++-- pybtc/test/block.py | 10 ++--- pybtc/transaction.py | 74 +++++++++++++++++++++++---------- 8 files changed, 90 insertions(+), 34 deletions(-) diff --git a/pybtc/_crypto/module_crypto.cpp b/pybtc/_crypto/module_crypto.cpp index 3339f8c..0f80edd 100644 --- a/pybtc/_crypto/module_crypto.cpp +++ b/pybtc/_crypto/module_crypto.cpp @@ -51,11 +51,23 @@ static PyObject* crypto_double_sha256(PyObject *, PyObject* args) { 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[] = { { "__decode_base58__", (PyCFunction)crypto_decode_base58, METH_VARARGS, nullptr }, { "__encode_base58__", (PyCFunction)crypto_encode_base58, METH_VARARGS, nullptr }, { "__double_sha256__", (PyCFunction)crypto_double_sha256, METH_VARARGS, nullptr }, + { "__sha256__", (PyCFunction)crypto_sha256, METH_VARARGS, nullptr }, { nullptr, nullptr, 0, nullptr } }; diff --git a/pybtc/block.py b/pybtc/block.py index 1f1be47..170fe52 100644 --- a/pybtc/block.py +++ b/pybtc/block.py @@ -7,7 +7,7 @@ from pybtc.transaction import Transaction 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"): raise ValueError("tx_format error, raw or decoded allowed") self["format"] = format @@ -52,7 +52,7 @@ class Block(dict): block_target = int.from_bytes(self["hash"], byteorder="little") self["difficulty"] = target_to_difficulty(block_target) 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 t in self["tx"].values(): self["amount"] += t["amount"] diff --git a/pybtc/crypto.py b/pybtc/crypto.py index e526bfc..3034ece 100644 --- a/pybtc/crypto.py +++ b/pybtc/crypto.py @@ -12,6 +12,9 @@ def __encode_base58__(h): def __double_sha256__(h): return _crypto.__double_sha256__(h) +def __sha256__(h): + return _crypto.__sha256__(h) + def __secp256k1_context_randomize__(seed = None): if seed is None: diff --git a/pybtc/functions/hash.py b/pybtc/functions/hash.py index 9600f1d..83f217d 100644 --- a/pybtc/functions/hash.py +++ b/pybtc/functions/hash.py @@ -2,6 +2,7 @@ from hashlib import new as hashlib_new from hashlib import sha256 as hashlib_sha256 from hashlib import sha512 as hashlib_sha512 from pybtc.crypto import __double_sha256__ +from pybtc.crypto import __sha256__ import hmac bytes_from_hex = bytes.fromhex @@ -9,7 +10,8 @@ bytes_from_hex = bytes.fromhex def sha256(h, hex=False): if isinstance(h, str): 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): @@ -18,6 +20,7 @@ def double_sha256(h, hex=False): h = bytes_from_hex(h) # if isinstance(h, bytearray): # h = bytes(h) + # return hashlib_sha256(hashlib_sha256(h).digest()).digest() return __double_sha256__(h).hex() if hex else __double_sha256__(h) diff --git a/pybtc/functions/script.py b/pybtc/functions/script.py index e85feb3..3bff0d0 100644 --- a/pybtc/functions/script.py +++ b/pybtc/functions/script.py @@ -38,8 +38,7 @@ def parse_script(script, segwit=True): try: script = bytes_from_hex(script) except: - pass - assert isinstance(script, bytes) + raise ValueError("hex encoded string required") l = len(script) if segwit: if l == 22 and script[0] == 0: diff --git a/pybtc/functions/tools.py b/pybtc/functions/tools.py index c24d868..c141b80 100644 --- a/pybtc/functions/tools.py +++ b/pybtc/functions/tools.py @@ -148,9 +148,16 @@ def read_var_int(stream): :param stream: io.BytesIO stream. :return: bytes. """ - read = stream.read - l = read(1) - return b"".join((l, read(get_var_int_len(l) - 1))) + l = stream.read(1) + if l[0] == 253: + 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): diff --git a/pybtc/test/block.py b/pybtc/test/block.py index 5c58fc7..04b970a 100644 --- a/pybtc/test/block.py +++ b/pybtc/test/block.py @@ -601,7 +601,7 @@ class BlockDeserializeTests(unittest.TestCase): fc = f.readline() qt = time.time() bt = ( - Block(fc[:-1], format="raw"), + Block(fc[:-1], format="raw", keep_raw_tx=False), ) print("decoded block", time.time() - qt ) import pickle @@ -613,10 +613,10 @@ class BlockDeserializeTests(unittest.TestCase): print("decoded block load", time.time() - qt) import cProfile - # cProfile.run("import pybtc;" - # "f = open('./pybtc/test/raw_block.txt');" - # "fc = f.readline();" - # "pybtc.Block(fc[:-1], format='decoded')") + cProfile.run("import pybtc;" + "f = open('./pybtc/test/raw_block.txt');" + "fc = f.readline();" + "pybtc.Block(fc[:-1], format='raw', keep_raw_tx=False)") # cProfile.run("import pybtc;" # "f = open('./pybtc/test/raw_block.txt');" # "fc = f.readline();" diff --git a/pybtc/transaction.py b/pybtc/transaction.py index 85e437b..efe8401 100644 --- a/pybtc/transaction.py +++ b/pybtc/transaction.py @@ -35,7 +35,8 @@ class Transaction(dict): :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"): raise ValueError("format error, raw or decoded allowed") self.auto_commit = auto_commit @@ -64,6 +65,8 @@ class Transaction(dict): if raw_tx is None: return + self["rawTx"] = [] + rtx = self["rawTx"].append self["amount"] = 0 sw = sw_len = 0 stream = self.get_stream(raw_tx) @@ -72,30 +75,48 @@ class Transaction(dict): tell = stream.tell seek = stream.seek # start deserialization - self["version"] = unpack('