block template class

This commit is contained in:
4tochka 2018-03-31 18:54:46 +04:00
parent ae47a5ffaf
commit 88d657f86c
2 changed files with 132 additions and 4 deletions

View File

@ -747,7 +747,7 @@ class Block():
len_coinbase = len(self.transactions[0].tx_in[0].sig_script.raw)
if extranonce_start < 0:
extranonce_start = len_coinbase + extranonce_start
return tx[:44 + extranonce_start], tx[44+ len_coinbase:]
return tx[:44 + extranonce_start], tx[44 + extranonce_start + extranonce_size:]
@classmethod
@ -787,5 +787,106 @@ class Block():
return hexlify(block).decode()
else:
return block
# class BlockTemplate():
# def __init__(self, data):
class BlockTemplate():
def __init__(self, data, coinbase_output_address, testnet = False, coinbase_message = "",
extranonce1 = "00000000",
extranonce1_size = 4,
extranonce2_size = 4):
self.testnet = testnet
self.version = hexlify(data["version"].to_bytes(4, "big")).decode()
self.previous_block_hash = hexlify(reverse_hash(s2rh(data["previousblockhash"]))).decode()
self.time = hexlify(data["curtime"].to_bytes(4, "big")).decode()
self.bits = data["bits"]
self.height = data["height"]
self.block_reward = 50 * 100000000 >> data["height"] // 210000
self.coinbasevalue = self.block_reward
self.extranonce1 = extranonce1
self.extranonce1_size = extranonce1_size
self.extranonce2 = "00000000"
self.extranonce2_size = extranonce2_size
self.coinbase_output_address = coinbase_output_address
self.sigoplimit = data["sigoplimit"]
self.weightlimit = data["weightlimit"]
self.sigop= 0
self.weight = 0
if type(coinbase_message) == bytes:
coinbase_message = hexlify(coinbase_message).decode()
self.coinbase_message = coinbase_message
self.transactions = list(data["transactions"])
self.txid_list = list()
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 = target2diff(self.target)
self.merkle_branches = [hexlify(i).decode() for i in merkle_branches([self.coinbase_tx.hash,] + self.txid_list)]
def scan_tx_list(self):
self.coinbasevalue = self.block_reward
self.sigop = 0
self.weight = 0
self.txid_list = list()
for tx in self.transactions:
txid = s2rh(tx["txid"])
self.coinbasevalue += tx["fee"]
self.weight += tx["weight"]
self.sigop += tx["sigops"]
self.txid_list.append(txid)
def calculate_commitment(self, witness):
wtxid_list = [b"\x00" * 32,]
if self.transactions:
for tx in self.transactions:
wtxid_list.append(s2rh(tx["hash"]))
return double_sha256(merkleroot(wtxid_list) + witness)
def split_coinbase(self):
tx = self.coinbase_tx.serialize()
len_coinbase = len(self.coinbase_tx.tx_in[0].sig_script.raw)
return hexlify(tx[:44 + len_coinbase]).decode(),\
hexlify(tx[44 + len_coinbase:]).decode()
def create_coinbase_transaction(self):
tx = Transaction(version = 1,tx_in = [], tx_out = [], witness= [])
coinbase = b'\x03' + self.height.to_bytes(4,'little') + unhexlify(self.coinbase_message)
assert len(coinbase) <= 100 - self.extranonce1_size - self.extranonce2_size
tx.tx_in = [Input((b'\x00'*32 ,0xffffffff), coinbase, 0xffffffff)]
tx.witness = [Witness([b'\x00'*32])]
commitment = self.calculate_commitment(tx.witness[0].witness[0])
tx.add_output_address(self.coinbasevalue, self.coinbase_output_address, self.testnet)
tx.add_output_script(0, b'j$\xaa!\xa9\xed' + commitment)
tx.coinbase = True
tx.recalculate_txid()
return tx
def get_job(self, job_id, clean_jobs = True):
"""
job_id - ID of the job. Use this ID while submitting share generated from this job.
prevhash - Hash of previous block.
coinb1 - Initial part of coinbase transaction.
coinb2 - Final part of coinbase transaction.
merkle_branch - List of hashes, will be used for calculation of merkle root. This is not a list of all
transactions, it only contains prepared hashes of steps of merkle tree algorithm. Please read some
materials for understanding how merkle trees calculation works.
version - Bitcoin block version.
nbits - Encoded current network difficulty
ntime - Current ntime/
clean_jobs - When true, server indicates that submitting shares from previous jobs don't have a
sense and such shares will be rejected. When this flag is set, miner should also drop all previous
jobs, so job_ids can be eventually rotated.
"""
return [job_id,
self.previous_block_hash,
self.coinb1,
self.coinb2,
self.merkle_branches,
self.version,
self.bits,
self.time,
clean_jobs]

View File

@ -447,12 +447,33 @@ def is_valid_signature_encoding(sig):
# Transaction encoding
#
def bits2target(bits):
if type(bits) == str:
bits = unhexlify(bits)
return int.from_bytes(bits[1:], 'big') * (2 ** (8 * (bits[0] - 3)))
def target2diff(target):
return 0x00000000FFFF0000000000000000000000000000000000000000000000000000 / target
def bits2diff(bits):
return target2diff(bits2target(bits))
def rh2s(tthash):
return hexlify(tthash[::-1]).decode()
def s2rh(hash_string):
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):
tx_hash_list = list(tx_hash_list)
if len(tx_hash_list) == 1:
@ -496,7 +517,13 @@ 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:
if type(h) == str:
h = unhexlify(h)
merkle_root = double_sha256(merkle_root + h)
return merkle_root
#
#
#