Skip to content

Commit

Permalink
Resolve TODOs, part2: wrap neon transaction type into Enum, expose he…
Browse files Browse the repository at this point in the history
…lpers and use it.
  • Loading branch information
evgenyzdanovich committed Jun 11, 2024
1 parent afc9eb8 commit babe019
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 20 deletions.
3 changes: 1 addition & 2 deletions common/neon/transaction_meta_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ def neon_tx_hash(self) -> EthTxHash:
@property
def effective_gas_price(self) -> int:
effective_gas_price = self.neon_tx.gas_price
# TODO EIP1559: expose transaction type as an enum and use it here.
if self.neon_tx.tx_type == 2:
if self.neon_tx.is_dynamic_gas_tx:
# Effective gas price is equal to base_fee_per_gas + math.ceil(priority_fee_spent / total_gas_used).
effective_gas_price = self.neon_tx.max_fee_per_gas - self.neon_tx.max_priority_fee_per_gas
# However, math.ceil does floating-point math and sometimes gives incorrect results due to precision.
Expand Down
49 changes: 35 additions & 14 deletions common/neon/transaction_model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from typing import Union, Any
from enum import IntEnum
from typing import Annotated, Union, Any

from typing_extensions import Self

Expand All @@ -9,9 +10,9 @@
from ..ethereum.transaction import EthTx
from ..utils.cached import cached_method, cached_property
from ..utils.format import str_fmt_object
from ..utils.pydantic import BaseModel, HexUIntField
from ..utils.pydantic import BaseModel, HexUIntField, HexUIntGenericSerializer

from pydantic import Field
from pydantic import Field, PlainValidator


_TX_MODEL_EXCLUDE_LIST = {
Expand All @@ -20,8 +21,21 @@
}


class NeonTxType(IntEnum):
Legacy = 0
# AccessList = 1 is yet to be supported.
DynamicGas = 2


NeonTxTypeField = Annotated[
NeonTxType,
PlainValidator(lambda v: NeonTxType(v)),
HexUIntGenericSerializer(lambda v: v.value),
]


class NeonTxModel(BaseModel):
tx_type: HexUIntField
tx_type: NeonTxTypeField
# None for legacy transaction (calculated from v), present for dynamic gas transaction.
tx_chain_id: HexUIntField | None = Field(default=None, serialization_alias="chain_id")
neon_tx_hash: EthTxHashField
Expand Down Expand Up @@ -65,14 +79,14 @@ def model_post_init(self, _ctx: Any) -> None:
@classmethod
def default(cls) -> Self:
return cls(
# TODO EIP1559: use tx_type=2 when ready.
tx_type=0,
tx_type=NeonTxType.DynamicGas,
neon_tx_hash=EthTxHash.default(),
from_address=EthAddress.default(),
to_address=EthAddress.default(),
contract=EthAddress.default(),
nonce=0,
gas_price_legacy=0,
max_fee_per_gas=0,
max_priority_fee_per_gas=0,
gas_limit=0,
value=0,
call_data=EthBinStr.default(),
Expand Down Expand Up @@ -110,14 +124,14 @@ def _from_rlp(cls, data: str | bytes | bytearray, raise_exception: bool) -> Self

return cls(
error=str(exc),
# TODO EIP1559: use tx_type=2 when ready.
tx_type=0,
tx_type=NeonTxType.DynamicGas,
neon_tx_hash=EthTxHash.default(),
from_address=EthAddress.default(),
to_address=EthAddress.default(),
contract=EthAddress.default(),
nonce=0,
gas_price_legacy=0,
max_fee_per_gas=0,
max_priority_fee_per_gas=0,
gas_limit=0,
value=0,
call_data=EthBinStr.default(),
Expand Down Expand Up @@ -174,13 +188,13 @@ def _to_eth_tx(self) -> EthTx:
def _from_tx_hash(cls, neon_tx_hash: EthTxHash) -> Self:
return cls(
neon_tx_hash=neon_tx_hash,
# TODO EIP1559: use tx_type=2 when ready.
tx_type=0,
tx_type=NeonTxType.DynamicGas,
from_address=EthAddress.default(),
to_address=EthAddress.default(),
contract=EthAddress.default(),
nonce=0,
gas_price_legacy=0,
max_fee_per_gas=0,
max_priority_fee_per_gas=0,
gas_limit=0,
value=0,
call_data=EthBinStr.default(),
Expand All @@ -190,6 +204,14 @@ def _from_tx_hash(cls, neon_tx_hash: EthTxHash) -> Self:
error=None,
)

@cached_property
def is_dynamic_gas_tx(self):
return self.tx_type == NeonTxType.DynamicGas

@cached_property
def is_legacy_tx(self):
return self.tx_type == NeonTxType.Legacy

def to_rlp_tx(self) -> bytes:
return self._to_eth_tx().to_bytes()

Expand All @@ -214,7 +236,6 @@ def gas_price(self) -> int:
if self.tx_type == 0:
return self.gas_price_legacy
else:
# TODO EIP1559: check usage across the code and validate if it's correct.
return self.max_fee_per_gas

# Overriding BaseModel to exclude gas price related fields based on transaction type.
Expand Down
3 changes: 3 additions & 0 deletions common/utils/pydantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ def _uint256_to_hex(value: int | None) -> str | None:
HexUInt8Field = Annotated[int, PlainValidator(_hex_to_int), PlainSerializer(_uint8_to_hex)]
HexUInt256Field = Annotated[int, PlainValidator(_hex_to_int), PlainSerializer(_uint256_to_hex)]

# For outside the module serialization customization, to not expose _uint_to_hex directly.
HexUIntGenericSerializer = lambda f: PlainSerializer(lambda v: _uint_to_hex(f(v)))


# Allows: None | "1" | 1
def _dec_to_int(value: str | int | None) -> int | None:
Expand Down
2 changes: 2 additions & 0 deletions indexer/base/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,8 @@ class _DeprecatedNeonTx(BaseModel):
error: str | None

def to_clean_copy(self) -> NeonTxModel:
# TODO EIP1559: The deprecated neon transaction model likely contains legacy tx type underneath.
# Clarify if it's exactly true all the time.
return NeonTxModel(
tx_type=self.tx_type,
neon_tx_hash=self.sig,
Expand Down
1 change: 1 addition & 0 deletions proxy/base/mp_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def nonce(self) -> int:
@property
def gas_price(self) -> int:
# this property is used for sorting, and can be changed by the mempool logic
# TODO EIP1559: should we rely upon max_priority_fee_per_gas?
return self.order_gas_price or self.neon_tx.gas_price

@property
Expand Down
1 change: 1 addition & 0 deletions proxy/mempool/transaction_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ async def _update_tx_order(self, tx: MpTxModel) -> MpTxResp | None:
# without this increasing
# the tx will be in the bottom of the execution queue,
# and as a result, it will be never executed
# TODO EIP1559: should we rely upon max_priority_fee_per_gas?
tx.set_gas_price(token.suggested_gas_price * 2)
return None

Expand Down
3 changes: 1 addition & 2 deletions proxy/rpc/np_block_transaction_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,7 @@ def from_raw(
# Take base_fee_per_gas from dynamic gas transactions, if there are any.
base_fee_per_gas = 0
for tx_meta in tx_list:
# TODO EIP1559: prettify tx_type access via enum or a separate method.
if tx_meta.neon_tx.tx_type == 2:
if tx_meta.neon_tx.is_dynamic_gas_tx:
base_fee_per_gas = max(
base_fee_per_gas, tx_meta.neon_tx.max_fee_per_gas - tx_meta.neon_tx.max_priority_fee_per_gas
)
Expand Down
4 changes: 2 additions & 2 deletions tests/neon/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def test_neon_tx_model(self):

neon_tx_str = (
"NeonTxModel("
"tx_type=0, "
"tx_type=Legacy, "
"neon_tx_hash=0x14a298c1eea89f42285948b7d51eeac2876ca7406c9784b9b90dd3591d156d64, "
"from_address=0x8d900bfA2353548a4631bE870f99939575551B60, "
"to_address=0x7917bC33EeA648809c285607579c9919FB864F8F, "
Expand Down Expand Up @@ -270,7 +270,7 @@ def test_eip1559_neon_tx_model(self):

neon_tx_str = (
"NeonTxModel("
"tx_type=2, "
"tx_type=DynamicGas, "
"neon_tx_hash=0x698787452047f9e2187f653a6e66fac0f8ea30d3c78bdeae80a7317c2a30fdd8, "
"from_address=0x8d99C04eDe67EF5c2936215f95Af1A11045EA298, "
"to_address=0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD, "
Expand Down

0 comments on commit babe019

Please sign in to comment.