Block class
This commit is contained in:
parent
3da185c241
commit
2a18e7a6af
100
pybtc/block.py
100
pybtc/block.py
@ -4,25 +4,91 @@ from struct import pack, unpack
|
|||||||
|
|
||||||
|
|
||||||
class Block(dict):
|
class Block(dict):
|
||||||
def __init__(self, block):
|
def __init__(self, raw_block=None, format="decoded", version=536870912, testnet=False):
|
||||||
s = get_stream(block)
|
if format not in ("decoded", "raw"):
|
||||||
self["header"] = s.read(80)
|
raise ValueError("tx_format error, raw or decoded allowed")
|
||||||
self["hash"] = double_sha256(self["header"])
|
self["format"] = format
|
||||||
self["version"] = unpack("<L", s.read(4))
|
self["testnet"] = testnet
|
||||||
|
self["header"] = None
|
||||||
|
self["hash"] = None
|
||||||
|
self["version"] = version
|
||||||
|
self["versionHex"] = hexlify(struct.pack(">L", version)).decode()
|
||||||
|
self["previousBlockHash"] = None
|
||||||
|
self["merkleRoot"] = None
|
||||||
|
self["tx"] = dict()
|
||||||
|
self["time"] = None
|
||||||
|
self["bits"] = None
|
||||||
|
self["nonce"] = None
|
||||||
|
self["weight"] = 0
|
||||||
|
self["size"] = 80
|
||||||
|
self["strippedSize"] = 80
|
||||||
|
self["amount"] = 0
|
||||||
|
self["height"] = None
|
||||||
|
self["difficulty"] = None
|
||||||
|
self["targetDifficulty"] = None
|
||||||
|
self["target"] = None
|
||||||
|
if raw_block is None:
|
||||||
|
return
|
||||||
|
self["size"] = len(raw_block) if isinstance(raw_block, bytes) else int(len(raw_block)/2)
|
||||||
|
s = self.get_stream(raw_block)
|
||||||
|
self["format"] = "raw"
|
||||||
|
self["version"] = unpack("<L", s.read(4))[0]
|
||||||
|
self["versionHex"] = hexlify(struct.pack(">L", self["version"])).decode()
|
||||||
self["previousBlockHash"] = s.read(32)
|
self["previousBlockHash"] = s.read(32)
|
||||||
self["merkleRoot"] = s.read(32)
|
self["merkleRoot"] = s.read(32)
|
||||||
self["time"] = unpack("<L", s.read(4))
|
self["time"] = unpack("<L", s.read(4))[0]
|
||||||
self["bits"] = s.read(4),
|
self["bits"] = s.read(4)
|
||||||
self["nonce"] = unpack("<L", s.read(4))
|
|
||||||
|
self["target"] = bits_to_target(unpack("<L", self["bits"])[0])
|
||||||
|
self["targetDifficulty"] = target_to_difficulty(self["target"])
|
||||||
|
self["target"] = self["target"].to_bytes(32, byteorder="little")
|
||||||
|
self["nonce"] = unpack("<L", s.read(4))[0]
|
||||||
s.seek(-80, 1)
|
s.seek(-80, 1)
|
||||||
# self["tx"] = {i: Transaction(s)
|
self["header"] = s.read(80)
|
||||||
# for i in range(var_int_to_int(read_var_int(s)))}
|
self["hash"] = double_sha256(self["header"])
|
||||||
self["weight"] = 0
|
block_target = int.from_bytes(self["hash"], byteorder="little")
|
||||||
self["size"] = 0
|
self["difficulty"] = target_to_difficulty(block_target)
|
||||||
self["strippedSize"] = 0
|
tx_count = var_int_to_int(read_var_int(s))
|
||||||
self["height"] = 0
|
self["tx"] = {i: Transaction(s, format="raw")
|
||||||
self["difficulty"] = 0
|
for i in range(tx_count)}
|
||||||
self["targetDifficulty"] = 0
|
for t in self["tx"].values():
|
||||||
self["target"] = 0
|
self["amount"] += t["amount"]
|
||||||
|
self["strippedSize"] += t["bSize"]
|
||||||
|
self["strippedSize"] += var_int_len(tx_count)
|
||||||
|
self["weight"] = self["strippedSize"] * 3 + self["size"]
|
||||||
|
if format == "decoded":
|
||||||
|
self.decode(testnet=testnet)
|
||||||
|
|
||||||
|
def decode(self, testnet=None):
|
||||||
|
self["format"] = "decoded"
|
||||||
|
if testnet is not None:
|
||||||
|
self["testnet"] = testnet
|
||||||
|
if isinstance(self["hash"], bytes):
|
||||||
|
self["hash"] = rh2s(self["hash"])
|
||||||
|
if isinstance(self["target"], bytes):
|
||||||
|
self["target"] = rh2s(self["target"])
|
||||||
|
if isinstance(self["previousBlockHash"], bytes):
|
||||||
|
self["previousBlockHash"] = rh2s(self["previousBlockHash"])
|
||||||
|
if "nextBlockHash" in self:
|
||||||
|
if isinstance(self["nextBlockHash"], bytes):
|
||||||
|
self["nextBlockHash"] = rh2s(self["nextBlockHash"])
|
||||||
|
if isinstance(self["merkleRoot"], bytes):
|
||||||
|
self["merkleRoot"] = rh2s(self["merkleRoot"])
|
||||||
|
if isinstance(self["header"], bytes):
|
||||||
|
self["header"] = hexlify(self["header"]).decode()
|
||||||
|
if isinstance(self["bits"], bytes):
|
||||||
|
self["bits"] = rh2s(self["bits"])
|
||||||
|
for i in self["tx"]:
|
||||||
|
self["tx"][i].decode(testnet=testnet)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
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
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,8 @@
|
|||||||
|
"""
|
||||||
|
Old code will be removed
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
|
|||||||
@ -21,10 +21,10 @@ 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, tx_format="decoded", version=1, lock_time=0, testnet=False):
|
def __init__(self, raw_tx=None, format="decoded", version=1, lock_time=0, testnet=False):
|
||||||
if tx_format not in ("decoded", "raw"):
|
if format not in ("decoded", "raw"):
|
||||||
raise TypeError("tx_format error, raw or decoded allowed")
|
raise ValueError("format error, raw or decoded allowed")
|
||||||
self["format"] = tx_format
|
self["format"] = format
|
||||||
self["testnet"] = testnet
|
self["testnet"] = testnet
|
||||||
self["segwit"] = False
|
self["segwit"] = False
|
||||||
self["txId"] = None
|
self["txId"] = None
|
||||||
@ -94,7 +94,7 @@ class Transaction(dict):
|
|||||||
for k in range(ic):
|
for k in range(ic):
|
||||||
self["vIn"][k]["txInWitness"] = [stream.read(var_int_to_int(read_var_int(stream))) \
|
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)))]
|
for c in range(var_int_to_int(read_var_int(stream)))]
|
||||||
sw_len = stream.tell() - sw + 2
|
sw_len = (stream.tell() - start) - sw + 2
|
||||||
|
|
||||||
self["lockTime"] = unpack('<L', stream.read(4))[0]
|
self["lockTime"] = unpack('<L', stream.read(4))[0]
|
||||||
|
|
||||||
@ -282,7 +282,8 @@ class Transaction(dict):
|
|||||||
self["format"] = "raw"
|
self["format"] = "raw"
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_stream(self, stream):
|
@staticmethod
|
||||||
|
def get_stream(stream):
|
||||||
if type(stream) != io.BytesIO:
|
if type(stream) != io.BytesIO:
|
||||||
if type(stream) == str:
|
if type(stream) == str:
|
||||||
stream = unhexlify(stream)
|
stream = unhexlify(stream)
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
# from .hash_functions import *
|
from .hash_functions import *
|
||||||
# from .integer import *
|
from .integer import *
|
||||||
# from .address_functions import *
|
from .address_functions import *
|
||||||
# from .address_class import *
|
from .address_class import *
|
||||||
# from .ecdsa import *
|
from .ecdsa import *
|
||||||
# from .transaction_deserialize import *
|
from .transaction_deserialize import *
|
||||||
from .transaction_constructor import *
|
from .transaction_constructor import *
|
||||||
|
from .sighash import *
|
||||||
|
|
||||||
# from .script_deserialize import *
|
# from .script_deserialize import *
|
||||||
# from .create_transaction import *
|
# from .create_transaction import *
|
||||||
from .sighash import *
|
from .block import *
|
||||||
# from .block import *
|
|
||||||
@ -104,7 +104,7 @@ class AddressClassTests(unittest.TestCase):
|
|||||||
redeem = "5221032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b2" \
|
redeem = "5221032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b2" \
|
||||||
"6473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b26473e2967b8fd403b4b544b8" \
|
"6473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b26473e2967b8fd403b4b544b8" \
|
||||||
"36e71abdfebb08d8c96d6953ae"
|
"36e71abdfebb08d8c96d6953ae"
|
||||||
a = address.ScriptAddress(redeem)
|
a = address.ScriptAddress(redeem, witness_version=None)
|
||||||
self.assertEqual(a.address, '3KCqqS6eznp3ucVPxtNkiYcVg6kQKNX9sg')
|
self.assertEqual(a.address, '3KCqqS6eznp3ucVPxtNkiYcVg6kQKNX9sg')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -587,17 +587,21 @@ block_a = """00000020358d4156e298db6a1158e7796d511e7c3076ab64fd10bed03c160000000
|
|||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class BlockDeserializeTests(unittest.TestCase):
|
class BlockDeserializeTests(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
print("\nTesting Block class deserialization:\n")
|
print("\nTesting Block class deserialization:\n")
|
||||||
|
|
||||||
def test_block_class(self):
|
def test_block_class(self):
|
||||||
block_c = "2000000000000000000029a1a0390376afd72db120d698c2d8ebc41c545c7d4bc2b9033c303dd3d09d455da1c587406820a4dd77c5aa3fcc546dcceb1becc639829c4fe6535e815a1a372b405cc0829701010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2303f88e130068747470733a5c6170692e6269746170732e636f6d20f251bec0cb000000ffffffff02c817a804000000001976a914d4e49947b9f545218cd20389244c249d3520545d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"
|
block_c = "2000000000000000000029a1a0390376afd72db120d698c2d8ebc41c545c7d4bc2b9033c303dd3d09d455da1c587406820a4dd77c5aa3fcc546dcceb1becc639829c4fe6535e815a1a372b405cc0829701010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2303f88e130068747470733a5c6170692e6269746170732e636f6d20f251bec0cb000000ffffffff02c817a804000000001976a914d4e49947b9f545218cd20389244c249d3520545d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
block_e = "2000000000000000000029a1a0390376afd72db120d698c2d8ebc41c545c7d4bc2b9033c303dd3d09d455da1c587406820a4dd77c5aa3fcc546dcceb1becc639829c4fe65a815e531a372b405cc0829701010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2303f88e130068747470733a5c6170692e6269746170732e636f6d20f251bec0cb000000ffffffff02c817a804000000001976a914d4e49947b9f545218cd20389244c249d3520545d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"
|
block_e = "2000000000000000000029a1a0390376afd72db120d698c2d8ebc41c545c7d4bc2b9033c303dd3d09d455da1c587406820a4dd77c5aa3fcc546dcceb1becc639829c4fe65a815e531a372b405cc0829701010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2303f88e130068747470733a5c6170692e6269746170732e636f6d20f251bec0cb000000ffffffff02c817a804000000001976a914d4e49947b9f545218cd20389244c249d3520545d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
l = block.Block(block_a)
|
l = block.Block(block_a, format="decoded")
|
||||||
print(l)
|
f = open('./test/raw_block.txt')
|
||||||
assert 0
|
fc = f.readline()
|
||||||
|
qt = time.time()
|
||||||
|
bt = block.Block(fc[:-1], format="decoded")
|
||||||
|
# self.assertEqual(time.time() - qt < 1, 1)
|
||||||
|
|
||||||
# print(">>>",block.bits)
|
# print(">>>",block.bits)
|
||||||
# print(">>>",block.hash)
|
# print(">>>",block.hash)
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -16,7 +16,7 @@ from pybtc import address_to_hash as address2hash160
|
|||||||
def decode_block_tx(block):
|
def decode_block_tx(block):
|
||||||
stream = get_stream(block)
|
stream = get_stream(block)
|
||||||
stream.seek(80)
|
stream.seek(80)
|
||||||
return {i: Transaction(stream, tx_format="raw") for i in range(var_int_to_int(read_var_int(stream)))}
|
return {i: Transaction(stream, format="raw") for i in range(var_int_to_int(read_var_int(stream)))}
|
||||||
|
|
||||||
|
|
||||||
class TransactionDeserializeTests(unittest.TestCase):
|
class TransactionDeserializeTests(unittest.TestCase):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user