Ejemplo n.º 1
0
 async def set_target(self, to_time):
     if not self.block_factory.special_min:
         await self.set_target_from_last_non_special_min(
             self.config.LatestBlock.block)
     # todo: keep block target at normal target, for header and block info.
     # Only tweak target at validation time, and don't include special_min into header
     if self.block_factory.index >= CHAIN.SPECIAL_MIN_FORK:  # TODO: use a CHAIN constant
         # print("test target", int(to_time), self.last_block_time)
         if self.block_factory.target == 0:
             # If the node is started when the current block is special_min, then we have a 0 target
             await self.set_target_as_previous_non_special_min()
             # print('target set to', self.block_factory.target)
         delta_t = int(to_time) - self.last_block_time
         if delta_t \
                 > CHAIN.special_min_trigger(self.config.network, self.block_factory.index):
             special_target = CHAIN.special_target(
                 self.block_factory.index, self.block_factory.target,
                 delta_t, self.config.network)
             self.block_factory.special_min = True
             self.block_factory.special_target = special_target
             self.block_factory.time = int(to_time)
         else:
             self.block_factory.special_min = False
     elif self.block_factory.index < CHAIN.SPECIAL_MIN_FORK:  # TODO: use a CHAIN constant
         if (int(to_time) - self.last_block_time) > self.target_block_time:
             self.block_factory.target = self.max_target
             self.block_factory.special_min = True
             self.block_factory.time = int(to_time)
         else:
             self.block_factory.special_min = False
Ejemplo n.º 2
0
    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))
Ejemplo n.º 3
0
    async def sync_bottom_up(self):
        #bottom up syncing

        last_latest = self.latest_block
        self.latest_block = self.config.LatestBlock.block
        if last_latest:
            if self.latest_block.index > last_latest.index:
                self.app_log.info(
                    'Block height: %s | time: %s' %
                    (self.latest_block.index,
                     datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))

        latest_consensus = await self.mongo.async_db.consensus.find_one({
            'index':
            self.latest_block.index + 1,
            'block.version':
            CHAIN.get_version_for_height(self.latest_block.index + 1),
            'ignore': {
                '$ne': True
            }
        })
        if latest_consensus:
            self.remove_pending_transactions_now_in_chain(latest_consensus)
            self.remove_fastgraph_transactions_now_in_chain(latest_consensus)
            latest_consensus = await Block.from_dict(latest_consensus['block'])
            if self.debug:
                self.app_log.info("Latest consensus_block {}".format(
                    latest_consensus.index))

            records = await self.mongo.async_db.consensus.find({
                'index':
                self.latest_block.index + 1,
                'block.version':
                CHAIN.get_version_for_height(self.latest_block.index + 1),
                'ignore': {
                    '$ne': True
                }
            }).to_list(length=100)
            for record in sorted(records,
                                 key=lambda x: int(x['block']['target'], 16)):
                try:
                    block = await Block.from_dict(record['block'])
                except:
                    continue
                blockchain = await Blockchain.init_async([block])
                if await self.integrate_blockchain_with_existing_chain(
                        blockchain):
                    return True
        else:
            #  this path should be for syncing only.
            #  Stack:
            #    search_network_for_new
            #    request_blocks
            #    getblocks <--- rpc request
            #    blocksresponse <--- rpc response
            #    integrate_blockchain_with_existing_chain
            return await self.search_network_for_new()
Ejemplo n.º 4
0
    async def integrate_block_with_existing_chain(self,
                                                  block: Block,
                                                  extra_blocks=None):
        """Even in case of retrace, this is the only place where we insert a new block into the block collection and update BU"""
        self.app_log.warning('integrate_block_with_existing_chain')
        try:
            # TODO: reorg the checks, to have the faster ones first.
            # Like, here we begin with checking every tx one by one, when <e did not even check index and provided hash matched previous one.
            bc = await Blockchain.init_async()
            result = await bc.test_block(block)
            if not result:
                return False

            # self.mongo.db.blocks.update({'index': block.index}, block.to_dict(), upsert=True)
            # self.mongo.db.blocks.remove({'index': {"$gt": block.index}}, multi=True)
            # todo: is this useful? can we have more blocks above? No because if we had, we would have raised just above
            await self.mongo.async_db.blocks.delete_many(
                {'index': {
                    "$gte": block.index
                }})
            db_block = block.to_dict()
            db_block['updated_at'] = time()
            await self.mongo.async_db.blocks.replace_one(
                {'index': block.index}, db_block, upsert=True)
            await self.mongo.async_db.miner_transactions.delete_many({
                'id': {
                    '$in':
                    [x.transaction_signature for x in block.transactions]
                }
            })
            await self.config.LatestBlock.update_latest_block()
            self.app_log.info("New block inserted for height: {}".format(
                block.index))
            latest_consensus = await self.mongo.async_db.consensus.find_one({
                'index':
                block.index + 1,
                'block.version':
                CHAIN.get_version_for_height(block.index + 1),
                'ignore': {
                    '$ne': True
                }
            })
            if not latest_consensus:
                await self.config.LatestBlock.block_checker(
                )  # This will trigger mining pool to generate a new block to mine
                if self.config.mp:
                    await self.config.mp.refresh()
                    await StratumServer.block_checker()
                if not self.syncing:
                    await self.config.nodeShared().send_block(
                        self.config.LatestBlock.block)
            return True
        except Exception as e:
            from traceback import format_exc
            self.app_log.warning("{}".format(format_exc()))
Ejemplo n.º 5
0
 async def get_previous_consensus_block_from_local(self, block):
     #table cleanup
     new_blocks = self.mongo.async_db.consensus.find({
         'block.hash':
         block.prev_hash,
         'block.index': (block.index - 1),
         'block.version':
         CHAIN.get_version_for_height((block.index - 1))
     })
     async for new_block in new_blocks:
         new_block = await Block.from_dict(new_block['block'])
         yield new_block
Ejemplo n.º 6
0
 async def init_async(cls):
     self = cls()
     self.config = get_config()
     self.mongo = self.config.mongo
     self.app_log = getLogger("tornado.application")
     self.target_block_time = CHAIN.target_block_time(self.config.network)
     self.max_target = CHAIN.MAX_TARGET
     self.inbound = {}
     self.connected_ips = {}
     self.last_block_time = 0
     self.index = 0
     last_block = await self.config.BU.get_latest_block()
     if last_block:
         self.last_block_time = int(last_block['time'])
         self.index = last_block['index']
     self.last_refresh = 0
     self.block_factory = None
     await self.refresh()
     return self
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
    async def test_block(self,
                         block,
                         extra_blocks=[],
                         simulate_last_block=None):
        try:
            block.verify()
        except Exception as e:
            self.config.app_log.warning(
                "Integrate block error 1: {}".format(e))
            return False

        async def get_txns(txns):
            for x in txns:
                yield x

        async def get_inputs(inputs):
            for x in inputs:
                yield x

        if block.index == 0:
            return True

        if simulate_last_block:
            last_block = simulate_last_block
        else:
            last_block_data = await self.config.mongo.async_db.blocks.find_one(
                {'index': block.index - 1})
            if last_block_data:
                last_block = await Block.from_dict(last_block_data)
            else:
                return False

        if block.index >= CHAIN.FORK_10_MIN_BLOCK:
            target = await CHAIN.get_target_10min(block.index, last_block,
                                                  block, extra_blocks)
        else:
            target = await CHAIN.get_target(block.index, last_block, block,
                                            extra_blocks)

        delta_t = int(time()) - int(last_block.time)
        special_target = CHAIN.special_target(block.index, block.target,
                                              delta_t,
                                              get_config().network)

        if block.index >= 35200 and delta_t < 600 and block.special_min:
            return False

        used_inputs = {}
        i = 0
        async for transaction in get_txns(block.transactions):
            if extra_blocks:
                transaction.extra_blocks = extra_blocks
            self.config.app_log.warning('verifying txn: {} block: {}'.format(
                i, block.index))
            i += 1
            try:
                await transaction.verify()
            except InvalidTransactionException as e:
                self.config.app_log.warning(e)
                return False
            except InvalidTransactionSignatureException as e:
                self.config.app_log.warning(e)
                return False
            except MissingInputTransactionException as e:
                self.config.app_log.warning(e)
                return False
            except NotEnoughMoneyException as e:
                self.config.app_log.warning(e)
                return False
            except Exception as e:
                self.config.app_log.warning(e)
                return False

            if transaction.inputs:
                failed = False
                used_ids_in_this_txn = []
                async for x in get_inputs(transaction.inputs):
                    txn = self.config.BU.get_transaction_by_id(x.id,
                                                               instance=True)
                    if not txn:
                        txn = await transaction.find_in_extra_blocks(x)
                        if not txn:
                            failed = True
                    if self.config.BU.is_input_spent(x.id,
                                                     transaction.public_key,
                                                     from_index=block.index):
                        failed = True
                    if x.id in used_ids_in_this_txn:
                        failed = True
                    if (x.id, transaction.public_key) in used_inputs:
                        failed = True
                    used_inputs[(x.id, transaction.public_key)] = transaction
                    used_ids_in_this_txn.append(x.id)
                if failed and block.index >= CHAIN.CHECK_DOUBLE_SPEND_FROM:
                    return False
                elif failed and block.index < CHAIN.CHECK_DOUBLE_SPEND_FROM:
                    continue

        if block.index >= 35200 and delta_t < 600 and block.special_min:
            self.config.app_log.warning(
                f'Failed: {block.index} >= {35200} and {delta_t} < {600} and {block.special_min}'
            )
            return False

        if int(block.index) > CHAIN.CHECK_TIME_FROM and int(block.time) < int(
                last_block.time):
            self.config.app_log.warning(
                f'Failed: {int(block.index)} > {CHAIN.CHECK_TIME_FROM} and {int(block.time)} < {int(last_block.time)}'
            )
            return False

        if last_block.index != (block.index -
                                1) or last_block.hash != block.prev_hash:
            self.config.app_log.warning(
                f'Failed: {last_block.index} != {(block.index - 1)} or {last_block.hash} != {block.prev_hash}'
            )
            return False

        if int(block.index) > CHAIN.CHECK_TIME_FROM and (
                int(block.time) <
            (int(last_block.time) + 600)) and block.special_min:
            self.config.app_log.warning(
                f'Failed: {int(block.index)} > {CHAIN.CHECK_TIME_FROM} and ({int(block.time)} < ({int(last_block.time)} + {600})) and {block.special_min}'
            )
            return False

        target_block_time = CHAIN.target_block_time(self.config.network)

        checks_passed = False
        if (block.index >= CHAIN.BLOCK_V5_FORK) and int(
                block.little_hash(), 16) < target:
            self.config.app_log.warning('5')
            checks_passed = True
        elif (int(block.hash, 16) < target):
            self.config.app_log.warning('6')
            checks_passed = True
        elif (block.special_min and int(block.hash, 16) < special_target):
            self.config.app_log.warning('7')
            checks_passed = True
        elif (block.special_min and block.index < 35200):
            self.config.app_log.warning('8')
            checks_passed = True
        elif (block.index >= 35200 and block.index < 38600
              and block.special_min and
              (int(block.time) - int(last_block.time)) > target_block_time):
            self.config.app_log.warning('9')
            checks_passed = True
        else:
            self.config.app_log.warning(
                "Integrate block error - index and time error")

        if not checks_passed:
            return False

        return True
Ejemplo n.º 9
0
    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
            }
        })
Ejemplo n.º 10
0
    async def on_miner_nonce(self,
                             nonce: str,
                             job: Job,
                             address: str = '') -> bool:
        nonce = nonce + job.extra_nonce.encode().hex()
        hash1 = self.block_factory.generate_hash_from_header(
            self.block_factory.index, self.block_factory.header, nonce)
        if self.block_factory.index >= CHAIN.BLOCK_V5_FORK:
            hash1_test = self.little_hash(hash1)
        else:
            hash1_test = hash1

        if (int(hash1_test, 16) > self.block_factory.target
                and self.config.network != 'regnet'
                and (self.block_factory.special_min
                     and int(hash1, 16) > self.block_factory.special_target)):
            return False
        block_candidate = await self.block_factory.copy()
        block_candidate.hash = hash1
        block_candidate.nonce = nonce

        if block_candidate.special_min:
            delta_t = int(block_candidate.time) - int(self.last_block_time)
            special_target = CHAIN.special_target(block_candidate.index,
                                                  block_candidate.target,
                                                  delta_t, self.config.network)
            block_candidate.special_target = special_target

        if (block_candidate.index >= 35200 and
            (int(block_candidate.time) - int(self.last_block_time)) < 600
                and block_candidate.special_min):
            self.app_log.warning(
                "Special min block too soon: hash {} header {} nonce {}".
                format(block_candidate.hash, block_candidate.header,
                       block_candidate.nonce))
            return False

        accepted = False

        if ((int(block_candidate.target) +
             0x0000F00000000000000000000000000000000000000000000000000000000000
             ) > int(hash1, 16) or
            (block_candidate.index >= CHAIN.BLOCK_V5_FORK and
             (int(block_candidate.target) +
              0x0000F00000000000000000000000000000000000000000000000000000000000
              ) > int(block_candidate.little_hash(), 16))):
            # submit share only now, not to slow down if we had a block
            await self.mongo.async_db.shares.update_one(
                {'hash': block_candidate.hash}, {
                    '$set': {
                        'address': address,
                        'index': block_candidate.index,
                        'hash': block_candidate.hash,
                        'nonce': nonce,
                        'time': int(time())
                    }
                },
                upsert=True)

            accepted = True

        if (int(block_candidate.target) > int(block_candidate.hash, 16)
                or (block_candidate.index >= CHAIN.BLOCK_V5_FORK
                    and int(block_candidate.target) > int(
                        block_candidate.little_hash(), 16))):
            block_candidate.signature = self.config.BU.generate_signature(
                block_candidate.hash, self.config.private_key)

            try:
                block_candidate.verify()
            except Exception as e:
                self.app_log.warning(
                    "Verify error {} - hash {} header {} nonce {}".format(
                        e, block_candidate.hash, block_candidate.header,
                        block_candidate.nonce))
                return False
            # accept winning block
            await self.accept_block(block_candidate)
            # Conversion to dict is important, or the object may change
            self.app_log.debug('block ok')

            return {
                'hash': block_candidate.hash,
                'nonce': nonce,
                'height': block_candidate.index,
                'id': block_candidate.signature
            }
        elif (block_candidate.special_min and
              (int(block_candidate.special_target) > int(
                  block_candidate.hash, 16))
              or (block_candidate.index >= CHAIN.BLOCK_V5_FORK
                  and block_candidate.special_min and
                  (int(block_candidate.special_target) > int(
                      block_candidate.little_hash(), 16)))):
            block_candidate.signature = self.config.BU.generate_signature(
                block_candidate.hash, self.config.private_key)

            try:
                block_candidate.verify()
            except Exception as e:
                self.app_log.warning(
                    "Verify error {} - hash {} header {} nonce {}".format(
                        e, block_candidate.hash, block_candidate.header,
                        block_candidate.nonce))
                return False
            # accept winning block
            await self.accept_block(block_candidate)
            # Conversion to dict is important, or the object may change
            self.app_log.debug('block ok - special_min')

            return {
                'hash': block_candidate.hash,
                'nonce': nonce,
                'height': block_candidate.index,
                'id': block_candidate.signature
            }

        if accepted:
            return {
                'hash': block_candidate.hash,
                'nonce': nonce,
                'height': block_candidate.index,
                'id': block_candidate.signature
            }
Ejemplo n.º 11
0
    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
            }
        })
Ejemplo n.º 12
0
    async def insert_block(self, block, stream):
        self.app_log.debug('insert_block')
        try:
            await self.mongo.async_db.blocks.delete_many(
                {'index': {
                    "$gte": block.index
                }})

            db_block = block.to_dict()

            db_block['updated_at'] = time()

            await self.mongo.async_db.blocks.replace_one(
                {'index': block.index}, db_block, upsert=True)

            await self.mongo.async_db.miner_transactions.delete_many({
                'id': {
                    '$in':
                    [x.transaction_signature for x in block.transactions]
                }
            })

            await self.config.LatestBlock.update_latest_block()

            self.app_log.info("New block inserted for height: {}".format(
                block.index))

            latest_consensus = await self.mongo.async_db.consensus.find_one({
                'index':
                block.index + 1,
                'block.version':
                CHAIN.get_version_for_height(block.index + 1),
                'ignore': {
                    '$ne': True
                }
            })

            if not latest_consensus:
                await self.config.LatestBlock.block_checker(
                )  # This will trigger mining pool to generate a new block to mine
                if not self.syncing:
                    if stream and stream.syncing:
                        return True
                    await self.config.nodeShared.send_block(
                        self.config.LatestBlock.block)

            if self.config.mp:
                if self.syncing:
                    return True
                try:
                    await self.config.mp.refresh()
                except Exception as e:
                    self.app_log.warning("{}".format(format_exc()))

                try:
                    await StratumServer.block_checker()
                except Exception as e:
                    self.app_log.warning("{}".format(format_exc()))

            return True
        except Exception as e:
            from traceback import format_exc
            self.app_log.warning("{}".format(format_exc()))
Ejemplo n.º 13
0
    async def sync_bottom_up(self):
        #bottom up syncing

        last_latest = self.latest_block
        self.latest_block = self.config.LatestBlock.block
        if last_latest:
            if self.latest_block.index > last_latest.index:
                self.app_log.info(
                    'Block height: %s | time: %s' %
                    (self.latest_block.index,
                     datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
        self.config.health.consensus.last_activity = time()
        latest_consensus = await self.mongo.async_db.consensus.find_one({
            'index':
            self.latest_block.index + 1,
            'block.version':
            CHAIN.get_version_for_height(self.latest_block.index + 1),
            'ignore': {
                '$ne': True
            }
        })
        if latest_consensus:
            self.remove_pending_transactions_now_in_chain(latest_consensus)
            self.remove_fastgraph_transactions_now_in_chain(latest_consensus)
            latest_consensus = await Block.from_dict(latest_consensus['block'])
            if self.debug:
                self.app_log.info("Latest consensus_block {}".format(
                    latest_consensus.index))

            records = await self.mongo.async_db.consensus.find({
                'index':
                self.latest_block.index + 1,
                'block.version':
                CHAIN.get_version_for_height(self.latest_block.index + 1),
                'ignore': {
                    '$ne': True
                }
            }).to_list(length=100)
            for record in sorted(records,
                                 key=lambda x: int(x['block']['target'], 16)):
                try:
                    block = await Block.from_dict(record['block'])
                except:
                    continue
                stream = await self.config.peer.get_peer_by_id(
                    record['peer']['rid'])
                if stream and hasattr(stream,
                                      'peer') and stream.peer.authenticated:
                    await self.block_queue.add(
                        ProcessingQueueItem(await Blockchain.init_async(block),
                                            stream))

            return True
        else:
            #  this path is for syncing only.
            #  Stack:
            #    search_network_for_new
            #    request_blocks
            #    getblocks <--- rpc request
            #    blocksresponse <--- rpc response
            #    process_block_queue
            return await self.search_network_for_new()
Ejemplo n.º 14
0
    async def test_block(self, block):
        try:
            block.verify()
        except Exception as e:
            self.config.app_log.warning("Integrate block error 1: {}".format(e))
            return False

        async def get_txns(txns):
            for x in txns:
                yield x

        async def get_inputs(inputs):
            for x in inputs:
                yield x

        if block.index == 0:
            return True

        last_block = await Block.from_dict(await self.config.mongo.async_db.blocks.find_one({'index': block.index - 1}))

        if block.index >= CHAIN.FORK_10_MIN_BLOCK:
            target = await CHAIN.get_target_10min(block.index, last_block, block)
        else:
            target = await CHAIN.get_target(block.index, last_block, block)

        delta_t = int(time()) - int(last_block.time)
        special_target = CHAIN.special_target(block.index, block.target, delta_t, get_config().network)

        if block.index >= 35200 and delta_t < 600 and block.special_min:
            return False

        used_inputs = {}
        i = 0
        async for transaction in get_txns(block.transactions):
            self.config.app_log.warning('verifying txn: {} block: {}'.format(i, block.index))
            i += 1
            try:
                await transaction.verify()
            except InvalidTransactionException as e:
                self.config.app_log.warning(e)
                return False
            except InvalidTransactionSignatureException as e:
                self.config.app_log.warning(e)
                return False
            except MissingInputTransactionException as e:
                self.config.app_log.warning(e)
            except NotEnoughMoneyException as e:
                self.config.app_log.warning(e)
                return False
            except Exception as e:
                self.config.app_log.warning(e)
                return False

            if transaction.inputs:
                failed = False
                used_ids_in_this_txn = []
                async for x in get_inputs(transaction.inputs):
                    if self.config.BU.is_input_spent(x.id, transaction.public_key, from_index=block.index):
                        failed = True
                    if x.id in used_ids_in_this_txn:
                        failed = True
                    if (x.id, transaction.public_key) in used_inputs:
                        failed = True
                    used_inputs[(x.id, transaction.public_key)] = transaction
                    used_ids_in_this_txn.append(x.id)
                if failed and block.index >= CHAIN.CHECK_DOUBLE_SPEND_FROM:
                    return False
                elif failed and block.index < CHAIN.CHECK_DOUBLE_SPEND_FROM:
                    continue

        if block.index >= 35200 and delta_t < 600 and block.special_min:
            self.config.app_log.warning('1')
            return False

        if int(block.index) > CHAIN.CHECK_TIME_FROM and int(block.time) < int(last_block.time):
            self.config.app_log.warning('2')
            return False

        if last_block.index != (block.index - 1) or last_block.hash != block.prev_hash:
            self.config.app_log.warning('3')
            return False

        if int(block.index) > CHAIN.CHECK_TIME_FROM and (int(block.time) < (int(last_block.time) + 600)) and block.special_min:
            self.config.app_log.warning('4')
            return False

        if block.index >= 35200 and delta_t < 600 and block.special_min:
            self.config.app_log.warning('5')
            return False

        target_block_time = CHAIN.target_block_time(self.config.network)

        checks_passed = False
        if (int(block.hash, 16) < target):
            self.config.app_log.warning('6')
            checks_passed = True
        elif (block.special_min and int(block.hash, 16) < special_target):
            self.config.app_log.warning('7')
            checks_passed = True
        elif (block.special_min and block.index < 35200):
            self.config.app_log.warning('8')
            checks_passed = True
        elif (block.index >= 35200 and block.index < 38600 and block.special_min and (int(block.time) - int(last_block.time)) > target_block_time):
            self.config.app_log.warning('9')
            checks_passed = True
        else:
            self.config.app_log.warning("Integrate block error - index and time error")

        if not checks_passed:
            return False

        return True