Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
afalaleev committed Jun 23, 2024
1 parent df6369a commit ebcc13d
Show file tree
Hide file tree
Showing 42 changed files with 797 additions and 696 deletions.
46 changes: 3 additions & 43 deletions common/ethereum/transaction.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Annotated, Final
from typing import Final

import eth_keys
import rlp
Expand All @@ -9,8 +9,7 @@

from .errors import EthError
from ..utils.cached import cached_property, cached_method
from ..utils.format import bytes_to_hex, hex_to_bytes
from ..utils.pydantic import PlainValidator, PlainSerializer
from ..utils.format import hex_to_bytes


class EthNoChainTx(rlp.Serializable):
Expand Down Expand Up @@ -66,14 +65,10 @@ def __init__(self, *args, **kwargs):

@classmethod
def from_raw(cls, s: bytes | bytearray | str) -> Self:
if isinstance(s, cls):
return s
elif isinstance(s, str):
if isinstance(s, str):
s = hex_to_bytes(s)
elif isinstance(s, bytearray):
s = bytes(s)
elif isinstance(s, dict):
s = cls.from_dict(s)

try:
return rlp.decode(s, cls)
Expand All @@ -92,38 +87,10 @@ def _copy_from_nochain_tx(cls, nochain_tx: EthNoChainTx) -> Self:
value_list += [0, 0, 0]
return cls(*value_list)

@classmethod
def from_dict(cls, d: dict) -> Self:
return cls(
nonce=int(d.get("nonce", 0)),
gas_price=int(d.get("gasPrice", 0)),
gas_limit=int(d.get("gas", 0)),
to_address=bytes.fromhex(d.get("to", "")),
value=int(d.get("value", 0)),
call_data=bytes.fromhex(d.get("data", "")),
v=int(d.get("v", 0)),
r=int(d.get("r", 0)),
s=int(d.get("s", 0)),
)

def to_dict(self) -> dict:
return {
"nonce": int(self.nonce),
"gasPrice": int(self.gas_price),
"gas": int(self.gas_limit),
"to": self.to_address,
"value": int(self.value),
"data": bytes_to_hex(self.call_data),
}

@cached_method
def to_bytes(self) -> bytes:
return rlp.encode(self)

@cached_method
def to_string(self) -> str:
return bytes_to_hex(self.to_bytes(), prefix="0x")

@property
def has_chain_id(self) -> bool:
return self.chain_id is not None
Expand Down Expand Up @@ -216,10 +183,3 @@ def contract(self) -> bytes | None:

contract_addr = rlp.encode((self.from_address, self.nonce))
return keccak(contract_addr)[-20:]


EthTxField = Annotated[
EthTx,
PlainValidator(EthTx.from_raw),
PlainSerializer(lambda v: v.to_string(), return_type=str),
]
21 changes: 3 additions & 18 deletions common/http/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import hashlib
import inspect
import re
import time
Expand Down Expand Up @@ -67,23 +66,6 @@ def from_raw(

return self

@cached_property
def ctx_id(self) -> str:
if ctx_id := getattr(self, "_ctx_id", None):
return ctx_id

size = len(self.request.body)
raw_value = f"{self.ip_addr}:{size}:{self.start_time_nsec}"
ctx_id = hashlib.md5(bytes(raw_value, "utf-8")).hexdigest()[:8]
self.set_property_value("_ctx_id", ctx_id)
return ctx_id

@cached_property
def chain_id(self) -> int:
chain_id = getattr(self, "_chain_id", None)
assert chain_id is not None
return chain_id

@cached_property
def body(self) -> str:
value = self.request.body
Expand Down Expand Up @@ -121,6 +103,9 @@ def set_property_value(self, name: str, value) -> Self:
self._prop_name_set.add(name)
return self

def get_property_value(self, name: str, default):
return getattr(self, name, default)


@dataclass(frozen=True)
class HttpMethod:
Expand Down
12 changes: 6 additions & 6 deletions common/neon/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
from pydantic.functional_validators import PlainValidator
from typing_extensions import Self

from ..ethereum.transaction import EthTx
from ..ethereum.hash import EthAddress
from .transaction_model import NeonTxModel
from ..utils.cached import cached_method, cached_property
from ..utils.format import bytes_to_hex, hex_to_bytes, hex_to_int

Expand Down Expand Up @@ -150,11 +150,11 @@ def private_key(self) -> eth_keys.keys.PrivateKey:
def sign_msg(self, data: bytes) -> eth_keys.keys.Signature:
return self.private_key.sign_msg(data)

def sign_transaction(self, tx: EthTx, chain_id: int) -> str:
tx = tx.to_dict()
tx["chainId"] = chain_id
signed_tx = eth_account.Account.sign_transaction(tx, self.private_key)
return signed_tx.raw_transaction.to_0x_hex()
def sign_tx(self, tx: NeonTxModel) -> bytes:
tx_dict = tx.to_eth_dict()
tx_dict["chainId"] = self._chain_id
signed_tx = eth_account.Account.sign_transaction(tx_dict, self.private_key)
return bytes(signed_tx.raw_transaction)

def __str__(self) -> str:
return self.to_string()
Expand Down
10 changes: 10 additions & 0 deletions common/neon/transaction_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,16 @@ def to_rlp_tx(self) -> bytes:

return tx.to_bytes()

def to_eth_dict(self) -> dict:
return dict(
nonce=self.nonce,
gasPrice=self.gas_price,
gas=self.gas_limit,
to=self.to_address.to_string(),
value=self.value,
data=self.call_data.to_string(),
)

@property
def has_chain_id(self) -> bool:
return self.chain_id is not None
Expand Down
16 changes: 8 additions & 8 deletions proxy/base/server.py → proxy/base/intl_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
from common.utils.process_pool import ProcessPool


class BaseProxyComponent:
def __init__(self, server: BaseProxyServer):
class BaseIntlProxyComponent:
def __init__(self, server: BaseIntlProxyServer):
self._server = server

@cached_property
Expand All @@ -32,17 +32,17 @@ def _msg_filter(self) -> LogMsgFilter:
return self._server._msg_filter # noqa


class BaseProxyApi(BaseProxyComponent, AppDataApi):
def __init__(self, server: BaseProxyServer) -> None:
class BaseProxyApi(BaseIntlProxyComponent, AppDataApi):
def __init__(self, server: BaseIntlProxyServer) -> None:
AppDataApi.__init__(self)
BaseProxyComponent.__init__(self, server)
BaseIntlProxyComponent.__init__(self, server)


class BaseProxyServer(AppDataServer):
class BaseIntlProxyServer(AppDataServer):
class _ProcessPool(ProcessPool):
def __init__(self, server: BaseProxyServer) -> None:
def __init__(self, server: BaseIntlProxyServer) -> None:
super().__init__()
self._server: BaseProxyServer | None = server
self._server: BaseIntlProxyServer | None = server

def _on_process_start(self) -> None:
self._server._on_process_start()
Expand Down
18 changes: 9 additions & 9 deletions proxy/base/op_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from common.ethereum.bin_str import EthBinStrField
from common.ethereum.hash import EthAddressField, EthAddress
from common.ethereum.transaction import EthTxField
from common.neon.transaction_model import NeonTxModel
from common.solana.pubkey import SolPubKey, SolPubKeyField
from common.solana.transaction_model import SolTxModel
from common.utils.cached import cached_method
Expand Down Expand Up @@ -81,26 +81,26 @@ class OpTokenSolAddressModel(BaseModel):
token_sol_address: SolPubKeyField


class OpSignEthMessageRequest(BaseModel):
ctx_id: str
eth_address: EthAddressField
class OpSignEthMsgRequest(BaseModel):
req_id: dict
sender: EthAddressField
data: EthBinStrField


class OpSignEthMessageResp(BaseModel):
signed_message: str | None = None
class OpSignEthMsgResp(BaseModel):
signed_msg: EthBinStrField
error: str | None = None


class OpSignEthTxRequest(BaseModel):
ctx_id: str
tx: EthTxField
req_id: dict
neon_tx: NeonTxModel
eth_address: EthAddressField
chain_id: int


class OpSignEthTxResp(BaseModel):
signed_tx: str | None = None
signed_tx: EthBinStrField
error: str | None = None


Expand Down
22 changes: 9 additions & 13 deletions proxy/base/op_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from common.app_data.client import AppDataClient
from common.ethereum.bin_str import EthBinStrField
from common.ethereum.hash import EthAddressField
from common.ethereum.transaction import EthTxField
from common.neon.transaction_model import NeonTxModel
from common.solana.pubkey import SolPubKey
from common.solana.transaction import SolTx
from common.solana.transaction_model import SolTxModel
Expand All @@ -17,8 +17,8 @@
OpResourceResp,
OpTokenSolAddressModel,
OpGetTokenSolAddressRequest,
OpSignEthMessageRequest,
OpSignEthMessageResp,
OpSignEthMsgRequest,
OpSignEthMsgResp,
OpSignEthTxRequest,
OpSignEthTxResp,
OpSignSolTxListRequest,
Expand Down Expand Up @@ -55,16 +55,12 @@ async def get_token_sol_address(self, req_id: dict, owner: SolPubKey, chain_id:
resp = await self._get_token_sol_address(req)
return resp.token_sol_address

async def sign_eth_message(
self, ctx_id: str, eth_address: EthAddressField, data: EthBinStrField
) -> OpSignEthMessageResp:
req = OpSignEthMessageRequest(ctx_id=ctx_id, eth_address=eth_address, data=data)
return await self._sign_eth_message(req)
async def sign_eth_msg(self, req_id: dict, sender: EthAddressField, data: EthBinStrField) -> OpSignEthMsgResp:
req = OpSignEthMsgRequest(req_id=req_id, sender=sender, data=data)
return await self._sign_eth_msg(req)

async def sign_eth_tx(
self, ctx_id: str, tx: EthTxField, eth_address: EthAddressField, chain_id: int
) -> OpSignEthTxResp:
req = OpSignEthTxRequest(ctx_id=ctx_id, tx=tx, eth_address=eth_address, chain_id=chain_id)
async def sign_eth_tx(self, req_id: dict, neon_tx: NeonTxModel, chain_id: int) -> OpSignEthTxResp:
req = OpSignEthTxRequest(req_id=req_id, neon_tx=neon_tx, chain_id=chain_id)
return await self._sign_eth_tx(req)

async def sign_sol_tx_list(self, req_id: dict, owner: SolPubKey, tx_list: Sequence[SolTx]) -> tuple[SolTx, ...]:
Expand Down Expand Up @@ -98,7 +94,7 @@ async def _free_resource(self, request: OpFreeResourceRequest) -> OpResourceResp
async def _get_token_sol_address(self, request: OpGetTokenSolAddressRequest) -> OpTokenSolAddressModel: ...

@AppDataClient.method(name="signEthMessage")
async def _sign_eth_message(self, request: OpSignEthMessageRequest) -> OpSignEthMessageResp: ...
async def _sign_eth_msg(self, request: OpSignEthMsgRequest) -> OpSignEthMsgResp: ...

@AppDataClient.method(name="signEthTransaction")
async def _sign_eth_tx(self, request: OpSignEthTxRequest) -> OpSignEthTxResp: ...
Expand Down
84 changes: 84 additions & 0 deletions proxy/base/rpc_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from __future__ import annotations

from typing import ClassVar

from pydantic import AliasChoices, Field
from typing_extensions import Self

from common.ethereum.bin_str import EthBinStrField, EthBinStr
from common.ethereum.hash import EthAddressField, EthHash32Field, EthAddress, EthTxHash
from common.jsonrpc.api import BaseJsonRpcModel
from common.neon.transaction_model import NeonTxModel
from common.neon_rpc.api import EmulNeonCallModel
from common.utils.pydantic import HexUIntField


class RpcAccessItemModel(BaseJsonRpcModel):
address: EthAddressField
storageKeys: list[EthHash32Field]


class RpcEthTxRequest(BaseJsonRpcModel):
txType: HexUIntField = Field(default=0, validation_alias="type")
fromAddress: EthAddressField = Field(
default=EthAddress.default(),
validation_alias=AliasChoices("from", "fromAddress"),
)
toAddress: EthAddressField = Field(
default=EthAddress.default(),
validation_alias=AliasChoices("to", "toAddress"),
)
data: EthBinStrField = Field(
default=EthBinStr.default(),
validation_alias=AliasChoices("data", "input"),
)
value: HexUIntField = Field(default=0)
nonce: HexUIntField = Field(default=0)

gas: HexUIntField = Field(default=2**64)
gasPrice: HexUIntField = Field(default=2**64)
maxFeePerGas: HexUIntField = Field(default=2**64)
maxPriorityFeePerGas: HexUIntField = Field(default=2**64)

accessList: list[RpcAccessItemModel] = Field(default_factory=list)
chainId: HexUIntField = Field(default=0)

_default: ClassVar[RpcEthTxRequest | None] = None

@classmethod
def default(cls) -> Self:
if not cls._default:
cls._default = cls(
fromAddress=EthAddress.default(),
toAddress=EthAddress.default(),
data=EthBinStr.default(),
)
return cls._default

def to_emulation_call(self, chain_id: int) -> EmulNeonCallModel:
return EmulNeonCallModel(
from_address=self.fromAddress,
to_address=self.toAddress,
value=self.value,
data=self.data.to_bytes(),
gas_limit=self.gas,
gas_price=self.gasPrice,
chain_id=chain_id
)

def to_neon_tx(self) -> NeonTxModel:
return NeonTxModel(
tx_type=self.txType,
neon_tx_hash=EthTxHash.default(),
from_address=self.fromAddress,
to_address=self.toAddress,
contract=EthAddress.default(),
nonce=self.nonce,
gas_price=self.gasPrice,
gas_limit=self.gas,
value=self.value,
call_data=self.data,
v=0,
r=0,
s=0,
)
Loading

0 comments on commit ebcc13d

Please sign in to comment.