8 from coinbasetx import CoinbaseTransaction
10 # Remove dependency to settings, coinbase extras should be
11 # provided from coinbaser
12 from stratum import settings
14 class BlockTemplate(halfnode.CBlock):
15 '''Template is used for generating new jobs for clients.
16 Let's iterate extranonce1, extranonce2, ntime and nonce
17 to find out valid bitcoin block!'''
19 coinbase_transaction_class = CoinbaseTransaction
21 def __init__(self, timestamper, coinbaser, job_id):
22 super(BlockTemplate, self).__init__()
25 self.timestamper = timestamper
26 self.coinbaser = coinbaser
28 self.prevhash_bin = '' # reversed binary form of prevhash
29 self.prevhash_hex = ''
33 #self.coinbase_hex = None
34 self.merkletree = None
36 self.broadcast_args = []
38 # List of 4-tuples (extranonce1, extranonce2, ntime, nonce)
39 # registers already submitted and checked shares
40 # There may be registered also invalid shares inside!
43 def fill_from_rpc(self, data):
44 '''Convert getblocktemplate result into BlockTemplate instance'''
46 #txhashes = [None] + [ binascii.unhexlify(t['hash']) for t in data['transactions'] ]
47 txhashes = [None] + [ util.ser_uint256(int(t['hash'], 16)) for t in data['transactions'] ]
48 mt = merkletree.MerkleTree(txhashes)
50 coinbase = self.coinbase_transaction_class(self.timestamper, self.coinbaser, data['coinbasevalue'],
51 data['coinbaseaux']['flags'], data['height'], settings.COINBASE_EXTRAS)
53 self.height = data['height']
54 self.nVersion = data['version']
55 self.hashPrevBlock = int(data['previousblockhash'], 16)
56 self.nBits = int(data['bits'], 16)
57 self.hashMerkleRoot = 0
60 self.vtx = [ coinbase, ]
62 for tx in data['transactions']:
63 t = halfnode.CTransaction()
64 t.deserialize(StringIO.StringIO(binascii.unhexlify(tx['data'])))
67 self.curtime = data['curtime']
68 self.timedelta = self.curtime - int(self.timestamper.time())
70 self.target = util.uint256_from_compact(self.nBits)
73 self.prevhash_bin = binascii.unhexlify(util.reverse_hash(data['previousblockhash']))
74 self.prevhash_hex = "%064x" % self.hashPrevBlock
76 self.broadcast_args = self.build_broadcast_args()
78 def register_submit(self, extranonce1, extranonce2, ntime, nonce):
79 '''Client submitted some solution. Let's register it to
80 prevent double submissions.'''
82 t = (extranonce1, extranonce2, ntime, nonce)
83 if t not in self.submits:
84 self.submits.append(t)
88 def build_broadcast_args(self):
89 '''Build parameters of mining.notify call. All clients
90 may receive the same params, because they include
91 their unique extranonce1 into the coinbase, so every
92 coinbase_hash (and then merkle_root) will be unique as well.'''
94 prevhash = binascii.hexlify(self.prevhash_bin)
95 (coinb1, coinb2) = [ binascii.hexlify(x) for x in self.vtx[0]._serialized ]
96 merkle_branch = [ binascii.hexlify(x) for x in self.merkletree._steps ]
97 version = binascii.hexlify(struct.pack(">i", self.nVersion))
98 nbits = binascii.hexlify(struct.pack(">I", self.nBits))
99 ntime = binascii.hexlify(struct.pack(">I", self.curtime))
102 return (job_id, prevhash, coinb1, coinb2, merkle_branch, version, nbits, ntime, clean_jobs)
104 def serialize_coinbase(self, extranonce1, extranonce2):
105 '''Serialize coinbase with given extranonce1 and extranonce2
107 (part1, part2) = self.vtx[0]._serialized
108 return part1 + extranonce1 + extranonce2 + part2
110 def check_ntime(self, ntime):
111 '''Check for ntime restrictions.'''
112 if ntime < self.curtime:
115 if ntime > (self.timestamper.time() + 1000):
116 # Be strict on ntime into the near future
122 def serialize_header(self, merkle_root_int, ntime_bin, nonce_bin):
123 '''Serialize header for calculating block hash'''
124 r = struct.pack(">i", self.nVersion)
125 r += self.prevhash_bin
126 r += util.ser_uint256_be(merkle_root_int)
128 r += struct.pack(">I", self.nBits)
132 def finalize(self, merkle_root_int, extranonce1_bin, extranonce2_bin, ntime, nonce):
133 '''Take all parameters required to compile block candidate.
134 self.is_valid() should return True then...'''
136 self.hashMerkleRoot = merkle_root_int
139 self.vtx[0].set_extranonce(extranonce1_bin + extranonce2_bin)
140 self.sha256 = None # We changed block parameters, let's reset sha256 cache