From 0878ebf6fc615fa29186738fb551b3a2b8604c46 Mon Sep 17 00:00:00 2001 From: Edinaldo Junior Date: Thu, 19 Dec 2024 03:24:51 -0300 Subject: [PATCH 01/30] feat: new metamask rpc endpoints --- backend/database_handler/accounts_manager.py | 4 +- .../transactions_processor.py | 52 +++++++- backend/protocol_rpc/endpoints.py | 119 +++++++++++++++++- 3 files changed, 171 insertions(+), 4 deletions(-) diff --git a/backend/database_handler/accounts_manager.py b/backend/database_handler/accounts_manager.py index 4b2838eac..9a08ea97a 100644 --- a/backend/database_handler/accounts_manager.py +++ b/backend/database_handler/accounts_manager.py @@ -1,7 +1,7 @@ # consensus/services/transactions_db_service.py from eth_account import Account -from eth_account._utils.validation import is_valid_address +from eth_utils import is_address from .models import CurrentState from backend.database_handler.errors import AccountNotFoundError @@ -38,7 +38,7 @@ def create_new_account_with_address(self, address: str): self.session.commit() def is_valid_address(self, address: str) -> bool: - return is_valid_address(address) + return is_address(address) def get_account(self, account_address: str) -> CurrentState | None: """Private method to retrieve an account from the data base""" diff --git a/backend/database_handler/transactions_processor.py b/backend/database_handler/transactions_processor.py index 75cec867e..d414baae8 100644 --- a/backend/database_handler/transactions_processor.py +++ b/backend/database_handler/transactions_processor.py @@ -4,7 +4,7 @@ from .models import Transactions from sqlalchemy.orm import Session -from sqlalchemy import or_, and_ +from sqlalchemy import or_, and_, desc from .models import TransactionStatus from eth_utils import to_bytes, keccak, is_address @@ -356,3 +356,53 @@ def set_transaction_timestamp_accepted( transaction.timestamp_accepted = timestamp_accepted else: transaction.timestamp_accepted = int(time.time()) + + + def get_highest_nonce(self) -> int: + transaction = ( + self.session.query(Transactions) + .order_by(desc(Transactions.nonce)) + .first() + ) + if transaction is None: + return 0 + return transaction.nonce + + + def get_transactions_for_block(self, block_number: int, include_full_tx: bool) -> dict: + transactions = ( + self.session.query(Transactions) + .filter(Transactions.nonce == block_number) + .all() + ) + + if not transactions: + return None + + block_hash = transactions[0].hash + parent_hash = "0x" + "0" * 64 # Placeholder for parent block hash + timestamp = transactions[0].timestamp_accepted or int(time.time()) + + if include_full_tx: + transaction_data = [ + self._parse_transaction_data(tx) for tx in transactions + ] + else: + transaction_data = [tx.hash for tx in transactions] + + block_details = { + "number": hex(block_number), + "hash": block_hash, + "parentHash": parent_hash, + "nonce": "0x" + "0" * 16, + "transactions": transaction_data, + "timestamp": hex(int(timestamp)), + "miner": "0x" + "0" * 40, + "difficulty": "0x1", + "gasUsed": "0x0", + "gasLimit": "0x0", + "size": "0x0", + "extraData": "0x", + } + + return block_details \ No newline at end of file diff --git a/backend/protocol_rpc/endpoints.py b/backend/protocol_rpc/endpoints.py index b312d3abb..ba0f13c9e 100644 --- a/backend/protocol_rpc/endpoints.py +++ b/backend/protocol_rpc/endpoints.py @@ -52,6 +52,7 @@ import base64 + ####### HELPER ENDPOINTS ####### def ping() -> str: return "OK" @@ -365,7 +366,7 @@ def get_balance( def get_transaction_count( - transactions_processor: TransactionsProcessor, address: str + transactions_processor: TransactionsProcessor, address: str, block: str ) -> int: return transactions_processor.get_transaction_count(address) @@ -527,6 +528,102 @@ def set_transaction_appeal( def set_finality_window_time(consensus: ConsensusAlgorithm, time: int) -> None: consensus.set_finality_window_time(time) +def get_chain_id() -> str: + return hex(61_999) + +def get_net_version() -> str: + return "61999" + +def get_block_number(transactions_processor: TransactionsProcessor) -> str: + transaction_count = transactions_processor.get_highest_nonce() + return hex(transaction_count) + +def get_block_by_number( + transactions_processor: TransactionsProcessor, block_number: str, full_tx: bool +) -> dict | None: + try: + block_number_int = int(block_number, 16) + except ValueError: + raise JSONRPCError(f"Invalid block number format: {block_number}") + + block_details = transactions_processor.get_transactions_for_block( + block_number_int, include_full_tx=full_tx + ) + + if not block_details: + raise JSONRPCError(f"Block not found for number: {block_number}") + + return block_details + + +def get_gas_price() -> str: + gas_price_in_wei = 20 * 10**9 + return hex(gas_price_in_wei) + +def get_transaction_receipt( + transactions_processor: TransactionsProcessor, + transaction_hash: str, +) -> dict | None: + + transaction = transactions_processor.get_transaction_by_hash(transaction_hash) + + if not transaction: + return None + + receipt = { + "transactionHash": transaction_hash, + "transactionIndex": hex(0), + "blockHash": transaction_hash, + "blockNumber": hex(transaction.get("block_number", 0)), + "from": transaction.get("from_address"), + "to": transaction.get("to_address") if transaction.get("to_address") else None, + "cumulativeGasUsed": hex(transaction.get("gas_used", 21000)), + "gasUsed": hex(transaction.get("gas_used", 21000)), + "contractAddress": transaction.get("contract_address") if transaction.get("contract_address") else None, + "logs": transaction.get("logs", []), + "logsBloom": "0x" + "00" * 256, + "status": hex(1 if transaction.get("status", True) else 0), + } + + return receipt + +def get_block_by_hash( + transactions_processor: TransactionsProcessor, + transaction_hash: str, + full_tx: bool = False, +) -> dict | None: + + transaction = transactions_processor.get_transaction_by_hash(transaction_hash) + + if not transaction: + return None + + block_details = { + "hash": transaction_hash, + "parentHash": "0x" + "00" * 32, + "number": hex(transaction.get("block_number", 0)), + "timestamp": hex(transaction.get("timestamp", 0)), + "nonce": "0x" + "00" * 8, + "transactionsRoot": "0x" + "00" * 32, + "stateRoot": "0x" + "00" * 32, + "receiptsRoot": "0x" + "00" * 32, + "miner": "0x" + "00" * 20, + "difficulty": "0x1", + "totalDifficulty": "0x1", + "size": "0x0", + "extraData": "0x", + "gasLimit": hex(transaction.get("gas_limit", 8000000)), + "gasUsed": hex(transaction.get("gas_used", 21000)), + "logsBloom": "0x" + "00" * 256, + "transactions": [], + } + + if full_tx: + block_details["transactions"].append(transaction) + else: + block_details["transactions"].append(transaction_hash) + + return block_details def register_all_rpc_endpoints( jsonrpc: JSONRPC, @@ -655,3 +752,23 @@ def register_all_rpc_endpoints( partial(set_finality_window_time, consensus), method_name="sim_setFinalityWindowTime", ) + register_rpc_endpoint(get_chain_id, method_name="eth_chainId") + register_rpc_endpoint(get_net_version, method_name="net_version") + register_rpc_endpoint( + partial(get_block_number, transactions_processor), + method_name="eth_blockNumber", + ) + register_rpc_endpoint( + partial(get_block_by_number, transactions_processor), + method_name="eth_getBlockByNumber", + ) + register_rpc_endpoint(get_gas_price, method_name="eth_gasPrice") + register_rpc_endpoint( + partial(get_transaction_receipt, transactions_processor), + method_name="eth_getTransactionReceipt", + ) + register_rpc_endpoint( + partial(get_block_by_hash, transactions_processor), + method_name="eth_getBlockByHash", + ) + From 52a01a258edefe18f9e77a731b58933b01913a87 Mon Sep 17 00:00:00 2001 From: Edinaldo Junior Date: Fri, 20 Dec 2024 06:22:05 -0300 Subject: [PATCH 02/30] feat: adding wallet to frontend and improving backend --- .../transactions_processor.py | 4 +- backend/protocol_rpc/endpoints.py | 5 +- .../components/Simulator/AccountSelect.vue | 28 +++++++--- .../Simulator/ContractMethodItem.vue | 13 +---- frontend/src/global.d.ts | 7 +++ frontend/src/hooks/useGenlayer.ts | 14 +++-- frontend/src/stores/accounts.ts | 56 +++++++++++++++---- frontend/tsconfig.app.json | 2 +- 8 files changed, 89 insertions(+), 40 deletions(-) create mode 100644 frontend/src/global.d.ts diff --git a/backend/database_handler/transactions_processor.py b/backend/database_handler/transactions_processor.py index 186beee23..02db47f1f 100644 --- a/backend/database_handler/transactions_processor.py +++ b/backend/database_handler/transactions_processor.py @@ -368,10 +368,10 @@ def set_transaction_appeal_failed(self, transaction_hash: str, appeal_failed: in transaction.appeal_failed = appeal_failed - def get_highest_nonce(self) -> int: + def get_highest_timestamp(self) -> int: transaction = ( self.session.query(Transactions) - .order_by(desc(Transactions.nonce)) + .order_by(desc(Transactions.timestamp_accepted)) .first() ) if transaction is None: diff --git a/backend/protocol_rpc/endpoints.py b/backend/protocol_rpc/endpoints.py index e9a133a78..c98be39c6 100644 --- a/backend/protocol_rpc/endpoints.py +++ b/backend/protocol_rpc/endpoints.py @@ -389,6 +389,9 @@ async def call( from_address = params["from"] if "from" in params else None data = params["data"] + if from_address is None: + return base64.b64encode(b'\x00' * 31 + b'\x01').decode("ascii") # Example: Return '1' as a uint256 + if from_address and not accounts_manager.is_valid_address(from_address): raise InvalidAddressError(from_address) @@ -536,7 +539,7 @@ def get_net_version() -> str: return "61999" def get_block_number(transactions_processor: TransactionsProcessor) -> str: - transaction_count = transactions_processor.get_highest_nonce() + transaction_count = transactions_processor.get_highest_timestamp() return hex(transaction_count) def get_block_by_number( diff --git a/frontend/src/components/Simulator/AccountSelect.vue b/frontend/src/components/Simulator/AccountSelect.vue index 03cbc71c8..1f3a01404 100644 --- a/frontend/src/components/Simulator/AccountSelect.vue +++ b/frontend/src/components/Simulator/AccountSelect.vue @@ -27,6 +27,10 @@ const handleCreateNewAccount = async () => { }); } }; + +const connectMetaMask = async () => { + await store.fetchMetaMaskAccount(); +};