def verify(self): getcontext().prec = 8 if int(self.version) != int(CHAIN.get_version_for_height(self.index)): raise Exception("Wrong version for block height", self.version, CHAIN.get_version_for_height(self.index)) txns = self.get_transaction_hashes() verify_merkle_root = self.get_merkle_root(txns) if verify_merkle_root != self.merkle_root: raise Exception("Invalid block merkle root") header = self.generate_header() hashtest = self.generate_hash_from_header(self.index, header, str(self.nonce)) # print("header", header, "nonce", self.nonce, "hashtest", hashtest) if self.hash != hashtest: getLogger("tornado.application").warning("Verify error hashtest {} header {} nonce {}".format(hashtest, header, self.nonce)) raise Exception('Invalid block hash') address = P2PKHBitcoinAddress.from_pubkey(bytes.fromhex(self.public_key)) try: # print("address", address, "sig", self.signature, "pubkey", self.public_key) result = verify_signature(base64.b64decode(self.signature), self.hash.encode('utf-8'), bytes.fromhex(self.public_key)) if not result: raise Exception("block signature1 is invalid") except: try: result = VerifyMessage(address, BitcoinMessage(self.hash.encode('utf-8'), magic=''), self.signature) if not result: raise except: raise Exception("block signature2 is invalid") # verify reward coinbase_sum = 0 for txn in self.transactions: if int(self.index) > CHAIN.CHECK_TIME_FROM and (int(txn.time) > int(self.time) + CHAIN.TIME_TOLERANCE): #yadacoin.core.config.CONFIG.mongo.db.miner_transactions.remove({'id': txn.transaction_signature}, multi=True) #raise Exception("Block embeds txn too far in the future") pass if txn.coinbase: for output in txn.outputs: coinbase_sum += float(output.value) fee_sum = 0.0 for txn in self.transactions: if not txn.coinbase: fee_sum += float(txn.fee) reward = CHAIN.get_block_reward(self.index) #if Decimal(str(fee_sum)[:10]) != Decimal(str(coinbase_sum)[:10]) - Decimal(str(reward)[:10]): """ KO for block 13949 0.02099999 50.021 50.0 Integrate block error 1 ('Coinbase output total does not equal block reward + transaction fees', 0.020999999999999998, 0.021000000000000796) """ if quantize_eight(fee_sum) != quantize_eight(coinbase_sum - reward): print(fee_sum, coinbase_sum, reward) raise Exception("Coinbase output total does not equal block reward + transaction fees", fee_sum, (coinbase_sum - reward))
async def get(self): def get_ticker(): return requests.get('https://safe.trade/api/v2/peatio/public/markets/tickers') try: if not hasattr(self.config, 'ticker'): self.config.ticker = get_ticker() self.config.last_update = time.time() if (time.time() - self.config.last_update) > (600 * 6): self.config.ticker = get_ticker() self.config.last_update = time.time() last_btc = self.config.ticker.json()['ydabtc']['ticker']['last'] except: last_btc = 0 await self.config.LatestBlock.block_checker() pool_public_key = self.config.pool_public_key if hasattr(self.config, 'pool_public_key') else self.config.public_key total_blocks_found = await self.config.mongo.async_db.blocks.count_documents( { 'public_key': pool_public_key } ) expected_blocks = 144 pool_blocks_found_list = await self.config.mongo.async_db.blocks.find( { 'public_key': pool_public_key, 'time': {'$gte': time.time() - ( 600 * 144 )} }, { '_id': 0 } ).sort([('index', -1)]).to_list(100) expected_blocks = 144 mining_time_interval = 240 shares_count = await self.config.mongo.async_db.shares.count_documents({'time': {'$gte': time.time() - mining_time_interval}}) if shares_count > 0: pool_hash_rate = (shares_count * 69905) / mining_time_interval else: pool_hash_rate = 0 net_blocks_found = self.config.mongo.async_db.blocks.find({'time': {'$gte': time.time() - ( 600 * 144 )}}) net_blocks_found = await net_blocks_found.to_list(length=expected_blocks*10) if len(net_blocks_found) > 0: avg_net_target = 0 for block in net_blocks_found: avg_net_target += int(block['target'], 16) avg_net_target = avg_net_target / len(net_blocks_found) net_difficulty = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffff / avg_net_target network_hash_rate = ((len(net_blocks_found)/expected_blocks)*net_difficulty * 2**32 / 600) else: net_difficulty = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffff / 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffff network_hash_rate = 0 miner_count_pool_stat = await self.config.mongo.async_db.pool_stats.find_one({'stat': 'miner_count'}) worker_count_pool_stat = await self.config.mongo.async_db.pool_stats.find_one({'stat': 'worker_count'}) payouts = await self.config.mongo.async_db.share_payout.find({}, {'_id': 0}).sort([('index', -1)]).to_list(100) self.render_as_json({ 'pool': { 'hashes_per_second': pool_hash_rate, 'miner_count': miner_count_pool_stat['value'], 'worker_count': worker_count_pool_stat['value'], 'payout_scheme': 'PPLNS', 'pool_fee': self.config.pool_take, 'min_payout': 0, 'url': getattr(self.config, 'pool_url', f'{self.config.peer_host}:{self.config.stratum_pool_port}'), 'last_five_blocks': [{'timestamp': x['time'], 'height': x['index']} for x in pool_blocks_found_list[:5]], 'blocks_found': total_blocks_found, 'fee': self.config.pool_take, 'payout_frequency': self.config.payout_frequency, 'payouts': payouts, 'blocks': pool_blocks_found_list[:100] }, 'network': { 'height': self.config.LatestBlock.block.index, 'reward': CHAIN.get_block_reward(self.config.LatestBlock.block.index), 'last_block': self.config.LatestBlock.block.time, 'hashes_per_second': network_hash_rate, 'difficulty': net_difficulty }, 'market': { 'last_btc': last_btc }, 'coin': { 'algo': 'randomx YDA', 'circulating': self.config.LatestBlock.block.index * 50, 'max_supply': 21000000 } })
async def generate( cls, transactions=None, public_key=None, private_key=None, force_version=None, index=0, force_time=None, prev_hash=None, nonce=None, target=CHAIN.MAX_TARGET ): config = get_config() app_log = getLogger("tornado.application") if force_version is None: version = CHAIN.get_version_for_height(index) else: version = force_version if force_time: xtime = str(int(force_time)) else: xtime = str(int(time.time())) index = int(index) if index == 0: prev_hash = '' elif prev_hash is None and index != 0: prev_hash = LatestBlock.block.hash transactions = transactions or [] transaction_objs = [] fee_sum = 0.0 used_sigs = [] used_inputs = {} for txn in transactions: try: if isinstance(txn, Transaction): transaction_obj = txn else: transaction_obj = Transaction.from_dict(txn) if transaction_obj.transaction_signature in used_sigs: print('duplicate transaction found and removed') continue await transaction_obj.verify() used_sigs.append(transaction_obj.transaction_signature) except: raise InvalidTransactionException("invalid transactions") try: if int(index) > CHAIN.CHECK_TIME_FROM and (int(transaction_obj.time) > int(xtime) + CHAIN.TIME_TOLERANCE): config.mongo.db.miner_transactions.remove({'id': transaction_obj.transaction_signature}, multi=True) app_log.debug("Block embeds txn too far in the future {} {}".format(xtime, transaction_obj.time)) continue if transaction_obj.inputs: failed = False used_ids_in_this_txn = [] for x in transaction_obj.inputs: if config.BU.is_input_spent(x.id, transaction_obj.public_key): failed = True if x.id in used_ids_in_this_txn: failed = True if (x.id, transaction_obj.public_key) in used_inputs: failed = True used_inputs[(x.id, transaction_obj.public_key)] = transaction_obj used_ids_in_this_txn.append(x.id) if failed: continue transaction_objs.append(transaction_obj) fee_sum += float(transaction_obj.fee) except Exception as e: await config.mongo.async_db.miner_transactions.delete_many({'id': transaction_obj.transaction_signature}) config.app_log.debug('Exception {}'.format(e)) continue block_reward = CHAIN.get_block_reward(index) coinbase_txn = await Transaction.generate( public_key=public_key, private_key=private_key, outputs=[{ 'value': block_reward + float(fee_sum), 'to': str(P2PKHBitcoinAddress.from_pubkey(bytes.fromhex(public_key))) }], coinbase=True ) transaction_objs.append(coinbase_txn) transactions = transaction_objs block = await cls.init_async( version=version, block_time=xtime, block_index=index, prev_hash=prev_hash, transactions=transactions, public_key=public_key, target=target ) txn_hashes = block.get_transaction_hashes() block.set_merkle_root(txn_hashes) block.target = target block.header = block.generate_header() if nonce: block.nonce = str(nonce) block.hash = block.generate_hash_from_header( block.index, block.header, str(block.nonce) ) block.signature = TU.generate_signature(block.hash, private_key) return block
async def get(self): def get_ticker(): return requests.get( 'https://safe.trade/api/v2/peatio/public/markets/tickers') try: if not hasattr(self.config, 'ticker'): self.config.ticker = get_ticker() self.config.last_update = time.time() if (time.time() - self.config.last_update) > (600 * 6): self.config.ticker = get_ticker() self.config.last_update = time.time() last_btc = self.config.ticker.json()['ydabtc']['ticker']['last'] except: last_btc = 0 shares_count = await self.config.mongo.async_db.shares.count_documents( {'index': { '$gte': self.config.LatestBlock.block.index - 10 }}) blocks_found = await self.config.mongo.async_db.share_payout.count_documents( {}) last_block_found_payout = await self.config.mongo.async_db.share_payout.find_one( {}, sort=[('index', -1)]) if last_block_found_payout: last_block_found = await self.config.mongo.async_db.blocks.find_one( {'index': last_block_found_payout['index']}) else: last_block_found = None prev_block = await self.config.mongo.async_db.blocks.find_one( {'index': self.config.LatestBlock.block.index - 10}) seconds_elapsed = int(self.config.LatestBlock.block.time) - int( prev_block['time']) expected_blocks = 144 difficulty = CHAIN.MAX_TARGET_V3 / self.config.LatestBlock.block.target net_blocks_found = self.config.mongo.async_db.blocks.find({ 'index': { '$gte': self.config.LatestBlock.block.index - 288 } }).sort([('index', -1)]) include_blocks = [] async for x in net_blocks_found: if int(x['time']) > time.time() - 600: include_blocks.append(x) network_hash_rate = ((len(include_blocks) / expected_blocks) * difficulty * 2**32 / 600) self.render_as_json({ 'pool': { 'hashes_per_second': (shares_count * 1000) / float( seconds_elapsed / 60 ), # it takes 1000H/s to produce 1 0x0000f... share per minute 'miner_count': len(self.config.poolServer.inbound_streams['Miner'].keys()), 'last_block': last_block_found['time'] if last_block_found else 0, 'payout_scheme': 'PPLNS', 'pool_fee': self.config.pool_take, 'blocks_found': blocks_found, 'min_payout': 0, 'url': f'{self.config.peer_host}:{self.config.stratum_pool_port}' }, 'network': { 'height': self.config.LatestBlock.block.index, 'reward': CHAIN.get_block_reward(self.config.LatestBlock.block.index), 'last_block': self.config.LatestBlock.block.time, 'hashes_per_second': network_hash_rate }, 'market': { 'last_btc': last_btc } })