def create_push_script(datums): # datums can be ints or strs res = [] for datum in datums: if isinstance(datum, (int, long)): if datum == -1 or 1 <= datum <= 16: res.append(chr(datum + 80)) continue negative = datum < 0 datum = math.natural_to_string(abs(datum)) if datum and ord(datum[0]) & 128: datum = '\x00' + datum if negative: datum = chr(ord(datum[0]) + 128) + datum[1:] datum = datum[::-1] if len(datum) < 76: res.append(chr(len(datum))) elif len(datum) <= 0xff: res.append(76) res.append(chr(len(datum))) elif len(datum) <= 0xffff: res.append(77) res.append(pack.IntType(16).pack(len(datum))) elif len(datum) <= 0xffffffff: res.append(78) res.append(pack.IntType(32).pack(len(datum))) else: raise ValueError('string too long') res.append(datum) return ''.join(res)
def _run(self): while True: if self.net_state['poll_connection'] is None: logger.warn( "Couldn't connect to any RPC servers, sleeping for 1") sleep(1) continue try: auxblock = self.coinserv.getauxblock() except Exception as e: logger.warn( "Unable to communicate with aux chain server. {}".format( e)) sleep(2) continue #logger.debug("Aux RPC returned: {}".format(auxblock)) new_merged_work = dict(hash=int(auxblock['hash'], 16), target=pack.IntType(256).unpack( auxblock['target'].decode('hex')), merged_proxy=self.coinserv, monitor=self) self.aux_state['chain_id'] = auxblock['chainid'] if new_merged_work != self.net_state['merged_work'].get( auxblock['chainid']): try: height = self.coinserv.getblockcount() except Exception as e: logger.warn( "Unable to communicate with aux chain server. {}". format(e)) sleep(2) continue logger.info( "New aux work announced! Diff {}. RPC returned: {}".format( bitcoin_data.target_to_difficulty( new_merged_work['target']), new_merged_work)) self.net_state['merged_work'][ auxblock['chainid']] = new_merged_work self.aux_state[ 'difficulty'] = bitcoin_data.target_to_difficulty( pack.IntType(256).unpack( auxblock['target'].decode('hex'))) # only push the job if there's a new block height discovered. if self.aux_state['height'] != height: self.aux_state['height'] = height self.monitor_network.generate_job(push=True, flush=self.flush) self.aux_state['work_restarts'] += 1 else: self.monitor_network.generate_job() self.aux_state['new_jobs'] += 1 sleep(self.work_interval)
def update(self, reason=None): if reason: self.logger.info( "Updating {} aux work from a signal recieved!".format( self.config['name'])) try: auxblock = self.call_rpc('getauxblock') except RPCException: sleep(2) return False new_merged_work = dict(hash=int(auxblock['hash'], 16), target=pack.IntType(256).unpack( auxblock['target'].decode('hex')), type=self.config['name']) if new_merged_work['hash'] != self.jobmanager.merged_work.get( auxblock['chainid'], {'hash': None})['hash']: # We fetch the block height so we can see if the hash changed # because of a new network block, or because new transactions try: height = self.call_rpc('getblockcount') except RPCException: sleep(2) return False self.logger.info( "New aux work announced! Diff {:,.4f}. Height {:,}".format( bitcoin_data.target_to_difficulty( new_merged_work['target']), height)) # add height to work spec for future logging new_merged_work['height'] = height self.jobmanager.merged_work[auxblock['chainid']] = new_merged_work self.current_net['difficulty'] = bitcoin_data.target_to_difficulty( pack.IntType(256).unpack(auxblock['target'].decode('hex'))) # only push the job if there's a new block height discovered. if self.current_net['height'] != height: self.current_net['height'] = height self.jobmanager.generate_job(push=True, flush=self.config['flush']) self.server[self.prefix + "work_restarts"].incr() self.server[self.prefix + "new_jobs"].incr() else: self.jobmanager.generate_job() self.server[self.prefix + "new_jobs"].incr() return True
def from_target_upper_bound(cls, target): n = math.natural_to_string(target) if n and ord(n[0]) >= 128: n = '\x00' + n bits2 = (chr(len(n)) + (n + 3 * chr(0))[:3])[::-1] bits = pack.IntType(32).unpack(bits2) return cls(bits)
def hash160(data): if data == '04ffd03de44a6e11b9917f3a29f9443283d9871c9d743ef30d5eddcd37094b64d1b3d8090496b53256786bf5c82932ec23c3b74d9f05a6f95a8b5529352656664b'.decode( 'hex'): return 0x384f570ccc88ac2e7e00b026d1690a3fca63dd0 # hack for people who don't have openssl - this is the only value that p2pool ever hashes return pack.IntType(160).unpack( hashlib.new('ripemd160', hashlib.sha256(data).digest()).digest())
def _check_new_jobs(self, signal=False): if signal: self.last_signal = time.time() self.logger.info( "Updating {} aux work from a signal recieved!".format( self.config['currency'])) try: auxblock = self.call_rpc('getauxblock') except RPCException: sleep(2) return False hash = int(auxblock['hash'], 16) if hash != self.last_work['hash']: # We fetch the block height so we can see if the hash changed # because of a new network block, or because new transactions try: height = self.call_rpc('getblockcount') except RPCException: sleep(2) return False target_int = pack.IntType(256).unpack( auxblock['target'].decode('hex')) self.last_work.update( dict(hash=hash, target=target_int, type=self.config['currency'], height=height, found_block=self.found_block, chainid=auxblock['chainid'])) # only push the job if there's a new block height discovered. new_block = False if self.current_net['height'] != height: self.current_net['height'] = height self._incr("work_restarts") self._incr("new_jobs") self.new_job.flush = self.config['flush'] new_block = True else: self._incr("new_jobs") self.new_job.flush = False self.new_job.set() self.new_job.clear() if new_block: self.current_net['last_block'] = time.time() self.current_net[ 'difficulty'] = bitcoin_data.target_to_difficulty( target_int) self.logger.info( "New aux block announced! Diff {:,.4f}. Height {:,}". format(self.current_net['difficulty'], height)) return True
class FloatingIntegerType(pack.Type): _inner = pack.IntType(32) def read(self, file): bits, file = self._inner.read(file) return FloatingInteger(bits), file def write(self, file, item): return self._inner.write(file, item.bits)
def script2_to_address(script2, net): try: pubkey = script2[1:-1] script2_test = pubkey_to_script2(pubkey) except: pass else: if script2_test == script2: return pubkey_to_address(pubkey, net) try: pubkey_hash = pack.IntType(160).unpack(script2[3:-2]) script2_test2 = pubkey_hash_to_script2(pubkey_hash) except: pass else: if script2_test2 == script2: return pubkey_hash_to_address(pubkey_hash, net)
def script2_to_human(script2, net): try: pubkey = script2[1:-1] script2_test = pubkey_to_script2(pubkey) except: pass else: if script2_test == script2: return 'Pubkey. Address: %s' % (pubkey_to_address(pubkey, net), ) try: pubkey_hash = pack.IntType(160).unpack(script2[3:-2]) script2_test2 = pubkey_hash_to_script2(pubkey_hash) except: pass else: if script2_test2 == script2: return 'Address. Address: %s' % (pubkey_hash_to_address( pubkey_hash, net), ) return 'Unknown. Script: %s' % (script2.encode('hex'), )
def found_block(self, address, worker, header, coinbase_raw, job): aux_data = job.merged_data[self.config['name']] self.block_stats['solves'] += 1 self.logger.info("New {} Aux block at height {}".format( self.config['name'], aux_data['height'])) aux_block = ( pack.IntType(256, 'big').pack(aux_data['hash']).encode('hex'), bitcoin_data.aux_pow_type.pack( dict( merkle_tx=dict( tx=bitcoin_data.tx_type.unpack(coinbase_raw), block_hash=bitcoin_data.hash256(header), merkle_link=job.merkle_link, ), merkle_link=bitcoin_data.calculate_merkle_link( aux_data['hashes'], aux_data['index']), parent_block_header=bitcoin_data.block_header_type.unpack( header), )).encode('hex'), ) retries = 0 while retries < 5: retries += 1 new_height = aux_data['height'] + 1 res = False try: res = self.coinserv.getauxblock(*aux_block) except (bitcoinrpc.CoinRPCException, socket.error, ValueError) as e: self.logger.error( "{} Aux block failed to submit to the server!".format( self.config['name']), exc_info=True) self.logger.error(getattr(e, 'error')) if res is True: self.logger.info("NEW {} Aux BLOCK ACCEPTED!!!".format( self.config['name'])) # Record it for the stats self.block_stats['accepts'] += 1 self.recent_blocks.append( dict(height=new_height, timestamp=int(time.time()))) # submit it to our reporter if configured to do so if self.config['send']: self.logger.info( "Submitting {} new block to reporter".format( self.config['name'])) # A horrible mess that grabs the required information for # reporting the new block. Pretty failsafe so at least # partial information will be reporter regardless try: hsh = self.coinserv.getblockhash(new_height) except Exception: self.logger.info("", exc_info=True) hsh = '' try: block = self.coinserv.getblock(hsh) except Exception: self.logger.info("", exc_info=True) try: trans = self.coinserv.gettransaction(block['tx'][0]) amount = trans['details'][0]['amount'] except Exception: self.logger.info("", exc_info=True) amount = -1 self.block_stats['last_solve_hash'] = hsh self.reporter.add_block( address, new_height, int(amount * 100000000), -1, "%0.6X" % bitcoin_data.FloatingInteger.from_target_upper_bound( aux_data['target']).bits, hsh, merged=self.config['reporting_id'], worker=worker) break # break retry loop if success else: self.logger.error( "{} Aux Block failed to submit to the server, " "server returned {}!".format(self.config['name'], res), exc_info=True) sleep(1) else: self.block_stats['rejects'] += 1 self.block_stats['last_solve_height'] = aux_data['height'] + 1 self.block_stats['last_solve_worker'] = "{}.{}".format(address, worker) self.block_stats['last_solve_time'] = datetime.datetime.utcnow()
def found_block(self, address, worker, header, coinbase_raw, job, start): aux_data = job.merged_data[self.config['currency']] new_height = aux_data['height'] + 1 self.block_stats['solves'] += 1 stale = new_height <= self.current_net['height'] self.logger.info("New {} Aux block at height {}".format( self.config['currency'], new_height)) aux_block = ( pack.IntType(256, 'big').pack(aux_data['hash']).encode('hex'), bitcoin_data.aux_pow_type.pack( dict( merkle_tx=dict( tx=bitcoin_data.tx_type.unpack(coinbase_raw), block_hash=bitcoin_data.hash256(header), merkle_link=job.merkle_link, ), merkle_link=bitcoin_data.calculate_merkle_link( aux_data['hashes'], aux_data['index']), parent_block_header=bitcoin_data.block_header_type.unpack( header), )).encode('hex'), ) retries = 0 while retries < 5: retries += 1 res = False try: res = self.call_rpc('getauxblock', *aux_block) except (CoinRPCException, socket.error, ValueError) as e: self.logger.error( "{} Aux block failed to submit to the server!".format( self.config['currency']), exc_info=True) self.logger.error(getattr(e, 'error')) if res is True or res is None: # Record it for the stats self.block_stats['accepts'] += 1 self.recent_blocks.append( dict(height=new_height, timestamp=int(time.time()))) # submit it to our reporter if configured to do so if self.config['send']: if start: submission_time = time.time() - start self.manager.log_event( "{name}.block_submission_{curr}:{t}|ms".format( name=self.manager.config['procname'], curr=self.config['currency'], t=submission_time * 1000)) hsh = hexlify( pack.IntType(256, 'big').pack(aux_data['hash'])) self.logger.info("{} BLOCK {}:{} accepted after {}".format( self.config['currency'], hsh, new_height, submission_time)) # A bit of a mess that grabs the required information for # reporting the new block. Pretty failsafe so at least # partial information will be reporter regardless block = None amount = 0 try: block = self.call_rpc('getblock', hsh) except Exception: self.logger.info("", exc_info=True) else: try: trans = self.call_rpc('gettxout', block['tx'][0], 0) amount = trans['value'] except Exception: self.logger.info("", exc_info=True) self.block_stats['last_solve_hash'] = hsh return dict( address=address, height=new_height, total_subsidy=int(amount * 100000000), fees=None, hex_bits="%0.6X" % bitcoin_data.FloatingInteger.from_target_upper_bound( aux_data['target']).bits, hex_hash=hsh, currency=self.config['currency'], merged=True, algo=self.config['algo'], worker=worker) break # break retry loop if success else: self.logger.error( "{} Aux Block height {} failed to submit to the server, " "server returned {}!".format(self.config['currency'], new_height, res), exc_info=True) sleep(1) else: if stale: self.block_stats['stale'] += 1 else: self.block_stats['rejects'] += 1 self.block_stats['last_solve_height'] = aux_data['height'] + 1 self.block_stats['last_solve_worker'] = "{}.{}".format(address, worker) self.block_stats['last_solve_time'] = datetime.datetime.utcnow()
def pubkey_hash_to_script2(pubkey_hash): return '\x76\xa9' + ('\x14' + pack.IntType(160).pack(pubkey_hash)) + '\x88\xac'
def hash256(data, hash_func=sha256d): return pack.IntType(256).unpack(sha256d(data))
self.bits), hex(self.target)) class FloatingIntegerType(pack.Type): _inner = pack.IntType(32) def read(self, file): bits, file = self._inner.read(file) return FloatingInteger(bits), file def write(self, file, item): return self._inner.write(file, item.bits) address_type = pack.ComposedType([ ('services', pack.IntType(64)), ('address', pack.IPV6AddressType()), ('port', pack.IntType(16, 'big')), ]) tx_type = pack.ComposedType([ ('version', pack.IntType(32)), ('tx_ins', pack.ListType( pack.ComposedType([ ('previous_output', pack.PossiblyNoneType( dict(hash=0, index=2**32 - 1), pack.ComposedType([ ('hash', pack.IntType(256)), ('index', pack.IntType(32)),
def hash256(data): return pack.IntType(256).unpack( hashlib.sha256(hashlib.sha256(data).digest()).digest())
def check_merged_block(mm_later): aux_work, index, hashes = mm_later if hash_int <= aux_work['target']: monitor = aux_work['monitor'] self.server_state['aux_state'][monitor.name]['solves'] += 1 self.logger.log(36, "New {} Aux Block identified!".format(monitor.name)) aux_block = ( pack.IntType(256, 'big').pack(aux_work['hash']).encode('hex'), bitcoin_data.aux_pow_type.pack(dict( merkle_tx=dict( tx=bitcoin_data.tx_type.unpack(job.coinbase.raw), block_hash=header_hash_int, merkle_link=job.merkle_link, ), merkle_link=bitcoin_data.calculate_merkle_link(hashes, index), parent_block_header=bitcoin_data.block_header_type.unpack(header), )).encode('hex'), ) retries = 0 while retries < 5: retries += 1 new_height = self.server_state['aux_state'][monitor.name]['height'] + 1 try: res = aux_work['merged_proxy'].getauxblock(*aux_block) except (CoinRPCException, socket.error, ValueError) as e: self.logger.error("{} Aux block failed to submit to the server {}!" .format(monitor.name), exc_info=True) self.logger.error(getattr(e, 'error')) if res is True: self.logger.info("NEW {} Aux BLOCK ACCEPTED!!!".format(monitor.name)) self.server_state['aux_state'][monitor.name]['block_solve'] = int(time()) self.server_state['aux_state'][monitor.name]['accepts'] += 1 self.server_state['aux_state'][monitor.name]['recent_blocks'].append( dict(height=new_height, timestamp=int(time()))) if monitor.send: self.logger.info("Submitting {} new block to celery".format(monitor.name)) try: hsh = aux_work['merged_proxy'].getblockhash(new_height) except Exception: self.logger.info("", exc_info=True) hsh = '' try: block = aux_work['merged_proxy'].getblock(hsh) except Exception: self.logger.info("", exc_info=True) try: trans = aux_work['merged_proxy'].gettransaction(block['tx'][0]) amount = trans['details'][0]['amount'] except Exception: self.logger.info("", exc_info=True) amount = -1 self.celery.send_task_pp( 'add_block', self.address, new_height, int(amount * 100000000), -1, "%0.6X" % bitcoin_data.FloatingInteger.from_target_upper_bound(aux_work['target']).bits, hsh, merged=monitor.celery_id) break # break retry loop if success else: self.logger.error( "{} Aux Block failed to submit to the server, " "server returned {}!".format(monitor.name, res), exc_info=True) sleep(1) else: self.server_state['aux_state'][monitor.name]['rejects'] += 1