vana
Advanced tools
+1
-1
| Metadata-Version: 2.1 | ||
| Name: vana | ||
| Version: 0.39.0 | ||
| Version: 0.40.0 | ||
| Summary: | ||
@@ -5,0 +5,0 @@ Home-page: https://github.com/vana-com/vana-framework |
+1
-1
| [tool.poetry] | ||
| name = "vana" | ||
| version = "0.39.0" | ||
| version = "0.40.0" | ||
| description = "" | ||
@@ -5,0 +5,0 @@ authors = ["Tim Nunamaker <tim@vana.com>", "Volodymyr Isai <volod@vana.com>", "Kahtaf Alam <kahtaf@vana.com>"] |
+1
-1
@@ -18,3 +18,3 @@ # The MIT License (MIT) | ||
| __version__ = "0.39.0" | ||
| __version__ = "0.40.0" | ||
@@ -21,0 +21,0 @@ import rich |
@@ -16,56 +16,5 @@ from threading import Lock | ||
| self.account = account | ||
| self._nonce_cache: Dict[str, int] = {} | ||
| self._last_nonce_refresh = 0 | ||
| self.nonce_refresh_interval = 60 | ||
| self._nonce_lock = Lock() | ||
| self.chain_id = self.web3.eth.chain_id | ||
| self._nonce_lock = Lock() | ||
| def _get_safe_nonce(self) -> Nonce: | ||
| """ | ||
| Get the next safe nonce, accounting for pending transactions. | ||
| Thread-safe implementation for concurrent transaction submissions. | ||
| Returns: | ||
| Nonce: Next safe nonce to use for transaction | ||
| """ | ||
| with self._nonce_lock: | ||
| current_time = time.time() | ||
| cache_key = self.account.address | ||
| should_refresh = ( | ||
| current_time - self._last_nonce_refresh > self.nonce_refresh_interval or | ||
| cache_key not in self._nonce_cache | ||
| ) | ||
| if should_refresh: | ||
| try: | ||
| # Get both confirmed and pending nonces | ||
| confirmed_nonce: Nonce = self.web3.eth.get_transaction_count(self.account.address, 'latest') | ||
| pending_nonce: Nonce = self.web3.eth.get_transaction_count(self.account.address, 'pending') | ||
| # Use max to account for pending transactions | ||
| new_nonce: Nonce = Nonce(max(int(confirmed_nonce), int(pending_nonce))) | ||
| # Only update if new nonce is higher than cached | ||
| cached_nonce: Nonce = Nonce(self._nonce_cache.get(cache_key, 0)) | ||
| self._nonce_cache[cache_key] = Nonce(max(int(new_nonce), int(cached_nonce))) | ||
| self._last_nonce_refresh = current_time | ||
| vana.logging.debug( | ||
| f"Nonce cache refreshed - Latest: {confirmed_nonce}, " | ||
| f"Pending: {pending_nonce}, " | ||
| f"Using: {self._nonce_cache[cache_key]}" | ||
| ) | ||
| except Exception as e: | ||
| vana.logging.error(f"Error refreshing nonce: {str(e)}") | ||
| if cache_key not in self._nonce_cache: | ||
| raise | ||
| # Get and increment the cached nonce atomically | ||
| nonce = self._nonce_cache[cache_key] | ||
| self._nonce_cache[cache_key] = Nonce(int(nonce) + 1) | ||
| return nonce | ||
| def _clear_pending_transactions(self, max_wait_time: int = 180): | ||
@@ -150,3 +99,3 @@ """ | ||
| timeout: int = 30, | ||
| clear_pending_transactions: bool = True | ||
| clear_pending_transactions: bool = False | ||
| ) -> Tuple[HexBytes, TxReceipt]: | ||
@@ -164,3 +113,2 @@ """ | ||
| base_gas_multiplier: Base multiplier for gas price on retries (default: 1.5) | ||
| max_gas_multiplier: Maximum allowed gas price multiplier (default: 5.0) | ||
| timeout: Timeout in seconds to wait for transaction receipt (default: 30) | ||
@@ -189,51 +137,55 @@ clear_pending_transactions: Attempt to clear pending transactions before sending (default: False) | ||
| try: | ||
| # Estimate gas with conservative buffer | ||
| gas_estimate = function.estimate_gas({ | ||
| 'from': account.address, | ||
| 'value': value, | ||
| 'chainId': self.chain_id | ||
| }) | ||
| gas_limit = int(gas_estimate * 2) | ||
| with self._nonce_lock: | ||
| # Get nonce directly from chain within lock | ||
| nonce = self.web3.eth.get_transaction_count(self.account.address, 'pending') | ||
| # Calculate gas price - use base price for first attempt | ||
| base_gas_price = self.web3.eth.gas_price | ||
| gas_multiplier = base_gas_multiplier * (1.5 ** retry_count) | ||
| gas_price = int(base_gas_price * gas_multiplier) | ||
| # Estimate gas with conservative buffer | ||
| gas_estimate = function.estimate_gas({ | ||
| 'from': account.address, | ||
| 'value': value, | ||
| 'chainId': self.chain_id, | ||
| 'nonce': nonce | ||
| }) | ||
| gas_limit = int(gas_estimate * 2) | ||
| # Get safe nonce and build transaction | ||
| nonce = self._get_safe_nonce() | ||
| tx = function.build_transaction({ | ||
| 'from': account.address, | ||
| 'value': value, | ||
| 'gas': gas_limit, | ||
| 'gasPrice': gas_price, | ||
| 'nonce': nonce, | ||
| 'chainId': self.chain_id | ||
| }) | ||
| # Calculate gas price - use base price for first attempt | ||
| base_gas_price = self.web3.eth.gas_price | ||
| gas_multiplier = base_gas_multiplier * (1.5 ** retry_count) | ||
| gas_price = int(base_gas_price * gas_multiplier) | ||
| try: | ||
| # Simulate transaction first to catch reverts | ||
| self.web3.eth.call({ | ||
| 'from': tx['from'], | ||
| 'to': tx['to'], | ||
| 'data': tx['data'], | ||
| 'value': tx['value'], | ||
| 'gas': tx['gas'], | ||
| 'gasPrice': tx['gasPrice'], | ||
| # Build transaction | ||
| tx = function.build_transaction({ | ||
| 'from': account.address, | ||
| 'value': value, | ||
| 'gas': gas_limit, | ||
| 'gasPrice': gas_price, | ||
| 'nonce': nonce, | ||
| 'chainId': self.chain_id | ||
| }) | ||
| except ContractLogicError as e: | ||
| vana.logging.error(f"Transaction would revert: {str(e)}") | ||
| raise Exception(f"Transaction would revert: {str(e)}") | ||
| signed_tx = self.web3.eth.account.sign_transaction(tx, account.key) | ||
| try: | ||
| # Simulate transaction first to catch reverts | ||
| self.web3.eth.call({ | ||
| 'from': tx['from'], | ||
| 'to': tx['to'], | ||
| 'data': tx['data'], | ||
| 'value': tx['value'], | ||
| 'gas': tx['gas'], | ||
| 'gasPrice': tx['gasPrice'], | ||
| }) | ||
| except ContractLogicError as e: | ||
| vana.logging.error(f"Transaction would revert: {str(e)}") | ||
| raise Exception(f"Transaction would revert: {str(e)}") | ||
| vana.logging.info( | ||
| f"Sending transaction with nonce {nonce}, " | ||
| f"gas price {gas_price} ({gas_multiplier:.1f}x base) " | ||
| f"(retry {retry_count})" | ||
| ) | ||
| signed_tx = self.web3.eth.account.sign_transaction(tx, account.key) | ||
| tx_hash = self.web3.eth.send_raw_transaction(signed_tx.rawTransaction) | ||
| vana.logging.info( | ||
| f"Sending transaction with nonce {nonce}, " | ||
| f"gas price {gas_price} ({gas_multiplier:.1f}x base) " | ||
| f"(retry {retry_count})" | ||
| ) | ||
| # Wait for receipt with timeout | ||
| tx_hash = self.web3.eth.send_raw_transaction(signed_tx.rawTransaction) | ||
| # Wait for receipt outside the lock since transaction is already submitted | ||
| start_time = time.time() | ||
@@ -240,0 +192,0 @@ while True: |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
455485
-0.42%12241
-0.32%