async def _get_logs(self, data, shard, decoder: Callable[[str], bytes]): start_block = data.get("fromBlock", "latest") end_block = data.get("toBlock", "latest") # TODO: not supported yet for "earliest" or "pending" block if (isinstance(start_block, str) and start_block != "latest") or (isinstance(end_block, str) and end_block != "latest"): return None # parse addresses / topics addresses, topics = [], [] if "address" in data: if isinstance(data["address"], str): addresses = [Address.deserialize(decoder(data["address"]))] elif isinstance(data["address"], list): addresses = [ Address.deserialize(decoder(a)) for a in data["address"] ] if shard is not None: addresses = [Address(a.recipient, shard) for a in addresses] if "topics" in data: for topic_item in data["topics"]: if isinstance(topic_item, str): topics.append([data_decoder(topic_item)]) elif isinstance(topic_item, list): topics.append([data_decoder(tp) for tp in topic_item]) branch = Branch.create(self.master.get_shard_size(), shard) logs = await self.master.get_logs(addresses, topics, start_block, end_block, branch) if logs is None: return None return loglist_encoder(logs)
async def eth_getTransactionCount(self, address, shard=None): address = Address.deserialize(address) if shard is not None: address = Address(address.recipient, shard) account_branch_data = await self.master.get_primary_account_data( address) return account_branch_data.transaction_count
async def eth_getBalance(self, address, shard=None): address = Address.deserialize(address) if shard is not None: address = Address(address.recipient, shard) account_branch_data = await self.master.get_primary_account_data(address) balance = account_branch_data.balance return balance
async def donate(self, from_address, to_address, value=hex(10 ** 18)): """Faucet function to send value (default 1 token) from from_address to to_address. from_address must be one of the addresses in genesis_data/alloc.json. Only allow one pending tx at a time. Return tx id if success else None """ if value > 100 * (10 ** 18): return None key = self.master.env.quark_chain_config.alloc_accounts.get( from_address.hex(), None ) if not key: return None from_address = Address.deserialize(from_address) to_address = Address.deserialize(to_address) # Do nothing if there is already a pending tx result = await self.master.get_transactions_by_address( from_address, bytes(1), 1 ) if result: tx_list, next_token = result if tx_list: return None account_branch_data = await self.master.get_primary_account_data(from_address) nonce = account_branch_data.transaction_count network_id = self.master.env.quark_chain_config.NETWORK_ID evm_tx = EvmTransaction( nonce, 10 ** 9, 30000, to_address.recipient, value, b"", from_full_shard_id=from_address.full_shard_id, to_full_shard_id=to_address.full_shard_id, network_id=network_id, ) evm_tx.sign(key) tx = Transaction(code=Code.create_evm_code(evm_tx)) success = await self.master.add_transaction(tx) if not success: return None return id_encoder(tx.get_hash(), from_address.full_shard_id)
async def getAccountData(self, address, block_height=None, include_shards=False): # do not allow specify height if client wants info on all shards if include_shards and block_height is not None: return None primary = None address = Address.deserialize(address) if not include_shards: account_branch_data = await self.master.get_primary_account_data( address, block_height) branch = account_branch_data.branch count = account_branch_data.transaction_count balances = account_branch_data.token_balances primary = { "fullShardId": quantity_encoder(branch.get_full_shard_id()), "shardId": quantity_encoder(branch.get_shard_id()), "chainId": quantity_encoder(branch.get_chain_id()), "balances": balances_encoder(balances), "transactionCount": quantity_encoder(count), "isContract": account_branch_data.is_contract, } return {"primary": primary} branch_to_account_branch_data = await self.master.get_account_data( address) shards = [] for branch, account_branch_data in branch_to_account_branch_data.items( ): balances = account_branch_data.token_balances data = { "fullShardId": quantity_encoder(branch.get_full_shard_id()), "shardId": quantity_encoder(branch.get_shard_id()), "chainId": quantity_encoder(branch.get_chain_id()), "balances": balances_encoder(balances), "transactionCount": quantity_encoder(account_branch_data.transaction_count), "isContract": account_branch_data.is_contract, } shards.append(data) if branch.get_full_shard_id( ) == self.master.env.quark_chain_config.get_full_shard_id_by_full_shard_key( address.full_shard_key): primary = data return {"primary": primary, "shards": shards}
async def getBalance(self, address, block_height=None): account_branch_data = await self.master.get_primary_account_data( Address.deserialize(address), block_height) branch = account_branch_data.branch balance = account_branch_data.balance return { "branch": quantity_encoder(branch.value), "shard": quantity_encoder(branch.get_shard_id()), "balance": quantity_encoder(balance), }
async def getBalances(self, address, block_height=None): account_branch_data = await self.master.get_primary_account_data( Address.deserialize(address), block_height) branch = account_branch_data.branch balances = account_branch_data.token_balances return { "branch": quantity_encoder(branch.value), "fullShardId": quantity_encoder(branch.get_full_shard_id()), "shardId": quantity_encoder(branch.get_shard_id()), "chainId": quantity_encoder(branch.get_chain_id()), "balances": balances_encoder(balances), }
async def getNextBlockToMine(self, coinbase_address, shard_mask_value, prefer_root=False): address = Address.deserialize(coinbase_address) is_root_block, block = await self.master.get_next_block_to_mine( address, shard_mask_value, prefer_root=prefer_root) if not block: return None return { "isRootBlock": is_root_block, "blockData": data_encoder(block.serialize()), }
async def getAccountData(self, address, block_height=None, include_shards=False): # do not allow specify height if client wants info on all shards if include_shards and block_height is not None: return None address = Address.deserialize(address) if not include_shards: account_branch_data = await self.master.get_primary_account_data( address, block_height) branch = account_branch_data.branch balance = account_branch_data.balance count = account_branch_data.transaction_count primary = { "branch": quantity_encoder(branch.value), "shard": quantity_encoder(branch.get_shard_id()), "balance": quantity_encoder(balance), "transactionCount": quantity_encoder(count), "isContract": account_branch_data.is_contract, } return {"primary": primary} branch_to_account_branch_data = await self.master.get_account_data( address) shard_size = self.master.get_shard_size() shards = [] for shard in range(shard_size): branch = Branch.create(shard_size, shard) account_branch_data = branch_to_account_branch_data[branch] data = { "branch": quantity_encoder(account_branch_data.branch.value), "shard": quantity_encoder(account_branch_data.branch.get_shard_id()), "balance": quantity_encoder(account_branch_data.balance), "transactionCount": quantity_encoder(account_branch_data.transaction_count), "isContract": account_branch_data.is_contract, } shards.append(data) if shard == address.get_shard_id(shard_size): primary = data return {"primary": primary, "shards": shards}
async def eth_getCode(self, address, shard=None): addr = Address.deserialize(address) if shard is not None: addr = Address(addr.recipient, shard) res = await self.master.get_code(addr, None) return data_encoder(res) if res is not None else None
async def getCode(self, address, block_height=None): res = await self.master.get_code(Address.deserialize(address), block_height) return data_encoder(res) if res is not None else None
async def getStorageAt(self, address, key, block_height=None): res = await self.master.get_storage_at(Address.deserialize(address), key, block_height) return data_encoder(res) if res is not None else None
async def getTransactionCount(self, address, block_height=None): account_branch_data = await self.master.get_primary_account_data( Address.deserialize(address), block_height) return account_branch_data.transaction_count