def create_mock_accounts_pending(self, data): accounts = data["accounts"] wallet = wallet_from_str(self.shared.wallet) assert data["threshold"] == "100000000000000000000000000" assert data["source"] blocks = {} for account_id in accounts: blocks[account_id] = "" for block in self.shared.pocketable_blocks: destination = ( block.destination if block.block_type == "send" else block.link_as_account ) if destination != account_id: continue try: account = wallet.account_map[destination] except KeyError: logger.info( "[MOCK] Account {} to check pending blocks for " "not in mock wallet".format(destination) ) continue already_pocketed = False for account_block in account.blocks: if not account_block.link_block: continue if account_block.link_block.block_hash != block.block_hash: continue if account_block.confirmed: already_pocketed = True break if already_pocketed: # Block has already been pocketed continue if blocks[account_id] == "": blocks[account_id] = {} blocks[account_id][block.block_hash] = { "amount": str(block.amount), "source": block.source } return { "blocks": blocks }
def do_POST(self): result = None shared = self.server.shared content_length = int(self.headers["Content-Length"]) post_data = self.rfile.read(content_length) post_data = json.loads(post_data) with self.server.lock: for mock_response in shared.req_responses: if mock_response.match(post_data): # If the request parameters correspond, send the # prepared mock response result = mock_response.get() if not result and shared.wallet: result = self.server.mocker.create_mock_response(post_data) if not result: logger.info( "Didn't find request {}".format(post_data) ) raise ValueError( "Didn't find a response for request {}".format(post_data) ) self.send_response(200) self.send_header("Content-type", "application/json; charset=utf-8") self.end_headers() self.wfile.write(bytes(json.dumps(result), "utf-8")) return
def wrapper(*args, **kwargs): wallet = args[0] with mock_node.lock: logger.info( "Hooking wallet to the mocked node from '{}'".format( wrapper._wrapped_method.__name__ ) ) mock_node.shared.wallet = wallet_to_str(wallet)
def create_mock_blocks_info(self, data): blocks = {} wallet = wallet_from_str(self.shared.wallet) for block_hash in data["hashes"]: found_block = None for account in wallet.accounts: if block_hash in account.block_map: block = account.block_map[block_hash] found_block = block break for block in self.shared.pocketable_blocks: if block.block_hash != block_hash: continue destination = ( block.destination if block.block_type == "send" else block.link_as_account ) try: account = wallet.account_map[destination] except KeyError: logger.info( "[MOCK] Account {} not in the mock wallet".format( destination ) ) found_block = block if found_block: blocks[block_hash] = { "amount": str(found_block.amount), "balance": str(found_block.balance), "contents": found_block.block.json(), # We can fake this for now "height": str(random.randint(2, 10)), "confirmed": "true", "local_timestamp": None } else: logger.info("[MOCK] Didn't find block {}".format(block_hash)) return { "blocks": blocks }
def wrapper(*args, **kwargs): wallet = args[0] with mock_node.lock: mock_wallet = wallet_from_str(mock_node.shared.wallet) if not mock_wallet: return logger.info( "Synchronizing mock wallet with the actual wallet " "from '{}'".format(wrapper._wrapped_method.__name__) ) for account in wallet.account_map.values(): account_id = account.account_id if account_id not in mock_wallet.account_map: mock_wallet.add_account( Account.from_dict(account.to_dict()) ) mock_account = mock_wallet.account_map[account_id] for block in account.blocks: if block.block_hash not in mock_account.block_map: mock_account.add_block( Block.from_dict(block.to_dict()) ) mock_block = mock_account.block_map[block.block_hash] if not mock_block.confirmed: mock_block.confirmed = block.confirmed if not mock_block.work: mock_block.work = block.work mock_block.difficulty = block.difficulty if not mock_block.signature: mock_block.signature = block.signature mock_account.confirmed_head = None mock_account.update_confirmed_head() mock_account.precomputed_work = copy.deepcopy( account.precomputed_work ) mock_node.shared.wallet = wallet_to_str(wallet) mock_node.synchronize_responses()
def create_mock_response(self, data): action = data["action"] try: if action == "account_history": return self.create_mock_account_history(data) elif action == "blocks_info": return self.create_mock_blocks_info(data) elif action == "accounts_pending": return self.create_mock_accounts_pending(data) elif action == "process": return self.create_mock_process(data) elif action == "active_difficulty": return self.create_mock_active_difficulty(data) elif action == "version": return self.create_mock_version(data) else: logger.info("[MOCK] Got non-mockable action '{}'".format(action)) except Exception as exc: logger.info("[MOCK] Mock function failed with {}".format(str(exc)))
async def handle_subscription(self, response): action = response["action"] topic = response["topic"] if action == "subscribe": self.subscriptions[topic] = response.get("options", {}) logger.info( "[MOCK] Subscribed %s %s", topic, self.subscriptions[topic] ) elif action == "unsubscribe": try: del self.subscriptions[topic] logger.info( "[MOCK] Unsubscribed from topic '%s'", topic ) except KeyError: logger.info( "[MOCK] Tried to unsubscribe from topic '%s' " "which is not active", topic )
def create_mock_process(self, data): block_data = data["block"] wallet = wallet_from_str(self.shared.wallet) block = RawBlock.from_json(block_data) if not block.signature: logger.info( "[MOCK] Trying to process unsigned block {}".format( block.block_hash ) ) return None if not block.work: logger.info( "[MOCK] Trying to process block with no work {}".format( block.block_hash ) ) return None account = wallet.account_map[block.account] mock_block = account.block_map[block.block_hash] if mock_block.confirmed: logger.info( "[MOCK] Trying to process confirmed block {}".format( block.block_hash ) ) return None logger.info( "[MOCK] Confirming block {}".format(block.block_hash) ) if self.shared.broadcast_fail_counter is not None: if self.shared.broadcast_fail_counter == 0: return { "error": "Gap source block" } else: self.shared.broadcast_fail_counter -= 1 if self.shared.difficulty_raise_counter is not None: if self.shared.difficulty_raise_counter == 0: self.shared.difficulty_raise_counter = None self.shared.work_difficulty = derive_work_difficulty( multiplier=1.15, base_difficulty=self.shared.work_difficulty ) return { "error": "Block work is less than threshold" } else: self.shared.difficulty_raise_counter -= 1 mock_block.confirmed = True self.shared.block_arrival_time[block.block_hash] = time.time() self.shared.wallet = wallet_to_str(wallet) return { "hash": block.block_hash }
def create_mock_account_history(self, data): account_id = data["account"] wallet = wallet_from_str(self.shared.wallet) assert data["raw"] assert data["reverse"] assert data["count"] == 500 head = data.get("head", None) result = { "account": account_id } try: account = wallet.account_map[account_id] except KeyError: logger.info( "[MOCK] Account {} not in mock wallet".format(account_id) ) if not account.blocks: return {"error": "Account not found"} account_entries = "" found_head = False for i, block in enumerate(account.blocks): block_hash = block.block_hash if block_hash == head: found_head = True elif i == 0 and head is None: found_head = True if found_head and block.confirmed: arrival_time = self.shared.block_arrival_time.get(block.block_hash, 0) broadcast_complete = block_hash in self.shared.broadcast_blocks # Don't report the block just yet if it's delayed, # unless it's been broadcast by WebSocket if not broadcast_complete and \ time.time() < arrival_time + self.shared.broadcast_delay: continue self.shared.broadcast_blocks.add(block_hash) if block.link_block: subtype = "receive" elif block.tx_type == "send/receive": subtype = "send" else: subtype = block.tx_type if account_entries == "": account_entries = [] account_entries.append({ "account": account.account_id, "amount": str(block.amount), "balance": str(block.balance), "hash": block.block_hash, "link": block.link, "local_timestamp": None, "previous": block.previous, "representative": block.representative, "signature": block.signature, "subtype": subtype, "type": block.block_type, "work": block.work }) result["history"] = account_entries return result