Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/config/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Configuration package for backend services."""
31 changes: 31 additions & 0 deletions backend/config/hardhat_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Centralized configuration for Hardhat settings."""

import os
from web3 import Web3


class HardhatConfig:
"""Configuration class for Hardhat network settings."""

@staticmethod
def get_port() -> str:
"""Get the Hardhat port from environment variable."""
return os.environ.get("HARDHAT_PORT", "8545")

@staticmethod
def get_base_url() -> str:
"""Get the Hardhat base URL from environment variable."""
return os.environ.get("HARDHAT_URL", "http://localhost")

@staticmethod
def get_full_url() -> str:
"""Get the complete Hardhat URL with port."""
port = HardhatConfig.get_port()
url = HardhatConfig.get_base_url()
return f"{url}:{port}"

@staticmethod
def get_web3_instance() -> Web3:
"""Get a Web3 instance connected to Hardhat network."""
hardhat_url = HardhatConfig.get_full_url()
return Web3(Web3.HTTPProvider(hardhat_url))
7 changes: 2 additions & 5 deletions backend/database_handler/transactions_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import time
from backend.domain.types import TransactionType
from web3 import Web3
import os
from backend.config.hardhat_config import HardhatConfig


class TransactionAddressFilter(Enum):
Expand Down Expand Up @@ -105,10 +105,7 @@ def __init__(
self.session = session

# Connect to Hardhat Network
port = os.environ.get("HARDHAT_PORT")
url = os.environ.get("HARDHAT_URL")
hardhat_url = f"{url}:{port}"
self.web3 = Web3(Web3.HTTPProvider(hardhat_url))
self.web3 = HardhatConfig.get_web3_instance()

@staticmethod
def _parse_transaction_data(transaction_data: Transactions) -> dict:
Expand Down
8 changes: 3 additions & 5 deletions backend/protocol_rpc/endpoint_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
from flask_jsonrpc.exceptions import JSONRPCError
from functools import partial, wraps
import requests
import os
import traceback
from backend.protocol_rpc.aio import run_in_main_server_loop
from backend.protocol_rpc.message_handler.base import MessageHandler
from backend.config.hardhat_config import HardhatConfig


def get_json_rpc_method_name(function: Callable, method_name: str | None = None):
Expand Down Expand Up @@ -67,9 +67,7 @@ def unfold(x: typing.Any):
def setup_eth_method_handler(jsonrpc: JSONRPC):
"""Forwards eth_ methods to Hardhat if no own implementation is available"""
app = jsonrpc.app
port = os.environ.get("HARDHAT_PORT")
url = os.environ.get("HARDHAT_URL")
HARDHAT_URL = f"{url}:{port}"
hardhat_url = HardhatConfig.get_full_url()

@app.before_request
def handle_eth_methods():
Expand All @@ -89,7 +87,7 @@ def handle_eth_methods():
try:
with requests.Session() as http:
result = http.post(
HARDHAT_URL,
hardhat_url,
json=request_json,
headers={"Content-Type": "application/json"},
).json()
Expand Down
36 changes: 34 additions & 2 deletions backend/protocol_rpc/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from sqlalchemy import Table
from sqlalchemy.orm import Session
import backend.validators as validators
from backend.config.hardhat_config import HardhatConfig

from backend.database_handler.contract_snapshot import ContractSnapshot
from backend.database_handler.llm_providers import LLMProviderRegistry
Expand Down Expand Up @@ -879,8 +880,39 @@ def get_gas_price() -> str:


def get_gas_estimate(data: Any) -> str:
gas_price_in_wei = 30 * 10**6
return hex(gas_price_in_wei)
"""
Estimate gas for a transaction using Hardhat service.
Falls back to a default value if the estimation fails.
"""
fallback_gas_estimate = 30 * 10**6

try:
web3 = HardhatConfig.get_web3_instance()
tx_params = {}
if isinstance(data, dict):
if "from" in data:
tx_params["from"] = data["from"]
if "to" in data:
tx_params["to"] = data["to"]
# Handle both 'data' and 'input' fields (some clients use 'input' instead of 'data')
if "data" in data:
tx_params["data"] = data["data"]
elif "input" in data:
tx_params["data"] = data["input"]
if "value" in data:
tx_params["value"] = (
int(data["value"], 16)
if isinstance(data["value"], str)
else data["value"]
)
if tx_params:
gas_estimate = web3.eth.estimate_gas(tx_params)
return hex(gas_estimate)
else:
return hex(fallback_gas_estimate)

except Exception:
return hex(fallback_gas_estimate)


def get_transaction_receipt(
Expand Down
8 changes: 2 additions & 6 deletions backend/rollup/consensus_service.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import json
import os
from web3 import Web3
from typing import Optional, Dict, Any
from pathlib import Path
from hexbytes import HexBytes
Expand All @@ -9,6 +7,7 @@
from backend.rollup.default_contracts.consensus_main import (
get_default_consensus_main_contract,
)
from backend.config.hardhat_config import HardhatConfig


class ConsensusService:
Expand All @@ -17,10 +16,7 @@ def __init__(self):
Initialize the ConsensusService class
"""
# Connect to Hardhat Network
port = os.environ.get("HARDHAT_PORT")
url = os.environ.get("HARDHAT_URL")
hardhat_url = f"{url}:{port}"
self.web3 = Web3(Web3.HTTPProvider(hardhat_url))
self.web3 = HardhatConfig.get_web3_instance()

self.web3_connected = self.web3.is_connected()

Expand Down
16 changes: 15 additions & 1 deletion tests/db-sqlalchemy/conftest.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import os
from typing import Iterable
from unittest.mock import patch, MagicMock

import pytest
from sqlalchemy import Engine, create_engine
from sqlalchemy.orm import Session, sessionmaker
from web3 import Web3
from web3.providers import BaseProvider

from backend.database_handler.models import Base
from backend.database_handler.transactions_processor import TransactionsProcessor
Expand Down Expand Up @@ -41,4 +44,15 @@ def session(engine: Engine) -> Iterable[Session]:

@pytest.fixture
def transactions_processor(session: Session) -> Iterable[TransactionsProcessor]:
yield TransactionsProcessor(session)
# Create a mock Web3 instance with proper provider
mock_provider = MagicMock(spec=BaseProvider)
web3_instance = Web3(mock_provider)
web3_instance.eth = MagicMock()
web3_instance.eth.accounts = ["0x0000000000000000000000000000000000000000"]

# Patch HardhatConfig.get_web3_instance to return our mock
with patch(
"backend.database_handler.transactions_processor.HardhatConfig.get_web3_instance",
return_value=web3_instance,
):
yield TransactionsProcessor(session)
20 changes: 4 additions & 16 deletions tests/db-sqlalchemy/transactions_processor_test.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,24 @@
from sqlalchemy.orm import Session
import pytest
from unittest.mock import patch, MagicMock
from unittest.mock import patch
import os
import math
from datetime import datetime
from web3 import Web3
from web3.providers import BaseProvider

from backend.database_handler.chain_snapshot import ChainSnapshot
from backend.database_handler.models import Transactions
from backend.database_handler.transactions_processor import TransactionStatus
from backend.database_handler.transactions_processor import TransactionsProcessor


@pytest.fixture(autouse=True)
def mock_env_and_web3():
def mock_env():
with patch.dict(
os.environ,
{
"HARDHAT_PORT": "8545",
"HARDHAT_URL": "http://localhost",
"HARDHAT_PRIVATE_KEY": "0x0123456789",
},
), patch("web3.Web3.HTTPProvider"):
web3_instance = Web3(MagicMock(spec=BaseProvider))
web3_instance.eth = MagicMock()
web3_instance.eth.accounts = ["0x0000000000000000000000000000000000000000"]
with patch(
"backend.database_handler.transactions_processor.Web3",
return_value=web3_instance,
):
yield
):
yield


def test_transactions_processor(transactions_processor: TransactionsProcessor):
Expand Down
3 changes: 2 additions & 1 deletion tests/hardhat/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ services:
hardhat:
condition: service_healthy
environment:
- HARDHAT_URL=http://hardhat:8545
- HARDHAT_URL=http://hardhat
- HARDHAT_PORT=8545
6 changes: 2 additions & 4 deletions tests/hardhat/test_hardhat.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from web3 import Web3
import json
from eth_account import Account
import os
from backend.config.hardhat_config import HardhatConfig


def test_eth_account():
Expand Down Expand Up @@ -41,8 +40,7 @@ def connect_to_hardhat():
Raises:
Exception: If the connection to the Hardhat network fails.
"""
hardhat_url = os.environ.get("HARDHAT_URL")
web3 = Web3(Web3.HTTPProvider(hardhat_url))
web3 = HardhatConfig.get_web3_instance()

# Check connection
if not web3.is_connected():
Expand Down