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;
}
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 }
};

View File

@ -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"]

View File

@ -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:

View File

@ -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)

View File

@ -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:

View File

@ -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):

View File

@ -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();"

View File

@ -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('<L', read(4))[0]
t = read(4)
rtx(t)
self["version"] = unpack('<L', t)[0]
n = read_var_int(stream)
rtx(n)
if n == b'\x00':
# segwit format
sw = 1
self["flag"] = read(1)
rtx(self["flag"])
n = read_var_int(stream)
rtx(n)
# inputs
ic = var_int_to_int(n)
for k in range(ic):
self["vIn"][k] = dict()
self["vIn"][k]["txId"] = read(32)
self["vIn"][k]["vOut"] = unpack('<L', read(4))[0]
self["vIn"][k]["scriptSig"] = read(var_int_to_int(read_var_int(stream)))
self["vIn"][k]["sequence"] = unpack('<L', read(4))[0]
rtx(self["vIn"][k]["txId"])
t = read(4)
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
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]["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["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"])
self["vOut"][k]["nType"] = s["nType"]
self["vOut"][k]["type"] = s["type"]
@ -110,16 +131,23 @@ class Transaction(dict):
if sw:
sw = tell() - start
for k in range(ic):
self["vIn"][k]["txInWitness"] = [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() - start) - sw + 2
self["vIn"][k]["txInWitness"] = []
t = read_var_int(stream)
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()
seek(start)
b = read(end - start)
self["rawTx"] = b
self["rawTx"] = b"".join(self["rawTx"])
self["size"] = end - start
self["bSize"] = end - start - sw_len
self["weight"] = self["bSize"] * 3 + self["size"]
@ -132,12 +160,16 @@ class Transaction(dict):
self["coinbase"] = False
if sw:
self["segwit"] = True
self["hash"] = double_sha256(b)
self["txId"] = double_sha256(b"%s%s%s" % (b[:4], b[6:sw],b[-4:]))
self["hash"] = double_sha256(self["rawTx"])
self["txId"] = double_sha256(b"".join((self["rawTx"][:4], self["rawTx"][6:sw], self["rawTx"][-4:])))
else:
self["segwit"] = False
self["txId"] = double_sha256(b)
self["txId"] = double_sha256(self["rawTx"])
self["hash"] = self["txId"]
if not keep_raw_tx:
self["rawTx"] = None
else:
self["rawTx"] = None
if self["format"] == "decoded":
self.decode()