Skip to content

Commit

Permalink
Merge pull request #310 from iwehf/vss
Browse files Browse the repository at this point in the history
manage tx nonce locally
  • Loading branch information
iwehf authored Jan 27, 2025
2 parents 31f995f + d27aa59 commit a967113
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 10 deletions.
17 changes: 9 additions & 8 deletions src/crynux_server/contracts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ async def _wait_receipt(w3: AsyncWeb3):
if not receipt["status"]:
async with catch_tx_revert_error(self.method):
tx = await w3.eth.get_transaction(self.tx_hash)
assert "to" in tx
assert "from" in tx
assert "value" in tx
assert "chainId" in tx
assert "gas" in tx
assert "gasPrice" in tx
assert "blockNumber" in tx
tx_params: TxParams = {
"to": tx["to"],
"from": tx["from"],
Expand Down Expand Up @@ -140,11 +147,8 @@ async def _deploy(w3: AsyncWeb3):
opt.update(**get_default_tx_option())

_contract_builder = w3.eth.contract(abi=self.abi, bytecode=self.bytecode)
async with self.w3_pool.with_nonce_lock():
async with self.w3_pool.with_nonce(w3) as nonce:
if "nonce" not in opt:
nonce = await w3.eth.get_transaction_count(
account=self.w3_pool.account, block_identifier="pending"
)
opt["nonce"] = nonce
_logger.debug(f"nonce: {nonce}")
if "from" not in opt:
Expand Down Expand Up @@ -198,11 +202,8 @@ async def _send_tx(w3: AsyncWeb3):
opt["value"] = w3.to_wei(value, "wei")

contract = w3.eth.contract(address=self._address, abi=self.abi)
async with self.w3_pool.with_nonce_lock():
async with self.w3_pool.with_nonce(w3) as nonce:
opt["from"] = self.w3_pool.account
nonce = await w3.eth.get_transaction_count(
account=self.w3_pool.account, block_identifier="pending"
)
opt["nonce"] = nonce
_logger.debug(f"nonce: {nonce}")
tx_func: AsyncContractFunction = getattr(contract.functions, method)
Expand Down
20 changes: 18 additions & 2 deletions src/crynux_server/contracts/w3_pool.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import re
import ssl
import warnings
from abc import ABC, abstractmethod
Expand All @@ -18,6 +19,7 @@
from web3 import AsyncHTTPProvider, AsyncWeb3, WebsocketProviderV2
from web3.middleware.signing import async_construct_sign_and_send_raw_middleware
from web3.providers.async_base import AsyncBaseProvider
from web3.types import Nonce
from websockets import ConnectionClosed

_logger = logging.getLogger(__name__)
Expand All @@ -31,6 +33,8 @@ class ProviderType(IntEnum):

_W3PoolCallback = Callable[[int], Awaitable[None]]

_invalid_nonce_pattern = re.compile(r"invalid nonce; got (\d+), expected (\d+)")


class W3Guard(ABC):
def __init__(
Expand Down Expand Up @@ -163,6 +167,7 @@ def __init__(

self._condition = Condition()
self._nonce_lock = Lock()
self._nonce: Optional[Nonce] = None

self._next_id = 1
self._guards: Dict[int, W3Guard] = {}
Expand Down Expand Up @@ -273,11 +278,22 @@ async def get(self) -> W3Guard:
return guard

@asynccontextmanager
async def with_nonce_lock(self):
async def with_nonce(self, w3: AsyncWeb3):
assert not self._closed, "w3 pool is closed"

async with self._nonce_lock:
yield
if self._nonce is None:
self._nonce = await w3.eth.get_transaction_count(self.account, "pending")
try:
yield self._nonce
except Exception as e:
m = _invalid_nonce_pattern.search(str(e))
if m is not None:
remote_nonce = int(m.group(2))
self._nonce = Nonce(remote_nonce)
raise e
else:
self._nonce = Nonce(self._nonce + 1)

async def close(self):
if not self._closed:
Expand Down

0 comments on commit a967113

Please sign in to comment.