From a5db757de39df6e08807e8917d8f924e4a68d76a Mon Sep 17 00:00:00 2001 From: Eric <5089238+emizzle@users.noreply.github.com> Date: Fri, 14 Mar 2025 09:46:05 +1100 Subject: [PATCH] fix: ethers no longer leaks AsyncLockError (#1146) * fix: ethers no longer leaks AsyncLockError * Add message to convertEthersEthers - adds a message to convertEthersError allowing contextual error messages - replaces try/except EthersError with convertEthersError (PR feedback) * bump ethers after PR merged upstream --- codex/contracts/market.nim | 117 +++++++++++++++++++------------------ vendor/nim-ethers | 2 +- 2 files changed, 60 insertions(+), 59 deletions(-) diff --git a/codex/contracts/market.nim b/codex/contracts/market.nim index 9079ac8a..58495b45 100644 --- a/codex/contracts/market.nim +++ b/codex/contracts/market.nim @@ -1,3 +1,4 @@ +import std/strformat import std/strutils import pkg/ethers import pkg/upraises @@ -49,11 +50,17 @@ func new*( proc raiseMarketError(message: string) {.raises: [MarketError].} = raise newException(MarketError, message) -template convertEthersError(body) = +func prefixWith(suffix, prefix: string, separator = ": "): string = + if prefix.len > 0: + return &"{prefix}{separator}{suffix}" + else: + return suffix + +template convertEthersError(msg: string = "", body) = try: body except EthersError as error: - raiseMarketError(error.msgDetail) + raiseMarketError(error.msgDetail.prefixWith(msg)) proc config( market: OnChainMarket @@ -71,7 +78,7 @@ proc config( proc approveFunds(market: OnChainMarket, amount: UInt256) {.async.} = debug "Approving tokens", amount - convertEthersError: + convertEthersError("Failed to approve funds"): let tokenAddress = await market.contract.token() let token = Erc20Token.new(tokenAddress, market.signer) discard await token.increaseAllowance(market.contract.address(), amount).confirm(1) @@ -86,8 +93,7 @@ method loadConfig*( market.configuration = some fetchedConfig return success() - except AsyncLockError, EthersError: - let err = getCurrentException() + except EthersError as err: return failure newException( MarketError, "Failed to fetch the config from the Marketplace contract: " & err.msg, @@ -100,13 +106,13 @@ method getZkeyHash*( return some config.proofs.zkeyHash method getSigner*(market: OnChainMarket): Future[Address] {.async.} = - convertEthersError: + convertEthersError("Failed to get signer address"): return await market.signer.getAddress() method periodicity*( market: OnChainMarket ): Future[Periodicity] {.async: (raises: [CancelledError, MarketError]).} = - convertEthersError: + convertEthersError("Failed to get Marketplace config"): let config = await market.config() let period = config.proofs.period return Periodicity(seconds: period) @@ -114,47 +120,47 @@ method periodicity*( method proofTimeout*( market: OnChainMarket ): Future[uint64] {.async: (raises: [CancelledError, MarketError]).} = - convertEthersError: + convertEthersError("Failed to get Marketplace config"): let config = await market.config() return config.proofs.timeout method repairRewardPercentage*( market: OnChainMarket ): Future[uint8] {.async: (raises: [CancelledError, MarketError]).} = - convertEthersError: + convertEthersError("Failed to get Marketplace config"): let config = await market.config() return config.collateral.repairRewardPercentage method requestDurationLimit*(market: OnChainMarket): Future[uint64] {.async.} = - convertEthersError: + convertEthersError("Failed to get Marketplace config"): let config = await market.config() return config.requestDurationLimit method proofDowntime*( market: OnChainMarket ): Future[uint8] {.async: (raises: [CancelledError, MarketError]).} = - convertEthersError: + convertEthersError("Failed to get Marketplace config"): let config = await market.config() return config.proofs.downtime method getPointer*(market: OnChainMarket, slotId: SlotId): Future[uint8] {.async.} = - convertEthersError: + convertEthersError("Failed to get slot pointer"): let overrides = CallOverrides(blockTag: some BlockTag.pending) return await market.contract.getPointer(slotId, overrides) method myRequests*(market: OnChainMarket): Future[seq[RequestId]] {.async.} = - convertEthersError: + convertEthersError("Failed to get my requests"): return await market.contract.myRequests method mySlots*(market: OnChainMarket): Future[seq[SlotId]] {.async.} = - convertEthersError: + convertEthersError("Failed to get my slots"): let slots = await market.contract.mySlots() debug "Fetched my slots", numSlots = len(slots) return slots method requestStorage(market: OnChainMarket, request: StorageRequest) {.async.} = - convertEthersError: + convertEthersError("Failed to request storage"): debug "Requesting storage" await market.approveFunds(request.totalPrice()) discard await market.contract.requestStorage(request).confirm(1) @@ -174,14 +180,14 @@ method getRequest*( except Marketplace_UnknownRequest, KeyError: warn "Cannot retrieve the request", error = getCurrentExceptionMsg() return none StorageRequest - except EthersError, AsyncLockError: - error "Cannot retrieve the request", error = getCurrentExceptionMsg() + except EthersError as e: + error "Cannot retrieve the request", error = e.msg return none StorageRequest method requestState*( market: OnChainMarket, requestId: RequestId ): Future[?RequestState] {.async.} = - convertEthersError: + convertEthersError("Failed to get request state"): try: let overrides = CallOverrides(blockTag: some BlockTag.pending) return some await market.contract.requestState(requestId, overrides) @@ -191,31 +197,26 @@ method requestState*( method slotState*( market: OnChainMarket, slotId: SlotId ): Future[SlotState] {.async: (raises: [CancelledError, MarketError]).} = - convertEthersError: - try: - let overrides = CallOverrides(blockTag: some BlockTag.pending) - return await market.contract.slotState(slotId, overrides) - except AsyncLockError as err: - raiseMarketError( - "Failed to fetch the slot state from the Marketplace contract: " & err.msg - ) + convertEthersError("Failed to fetch the slot state from the Marketplace contract"): + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return await market.contract.slotState(slotId, overrides) method getRequestEnd*( market: OnChainMarket, id: RequestId ): Future[SecondsSince1970] {.async.} = - convertEthersError: + convertEthersError("Failed to get request end"): return await market.contract.requestEnd(id) method requestExpiresAt*( market: OnChainMarket, id: RequestId ): Future[SecondsSince1970] {.async.} = - convertEthersError: + convertEthersError("Failed to get request expiry"): return await market.contract.requestExpiry(id) method getHost( market: OnChainMarket, requestId: RequestId, slotIndex: uint64 ): Future[?Address] {.async.} = - convertEthersError: + convertEthersError("Failed to get slot's host"): let slotId = slotId(requestId, slotIndex) let address = await market.contract.getHost(slotId) if address != Address.default: @@ -226,11 +227,11 @@ method getHost( method currentCollateral*( market: OnChainMarket, slotId: SlotId ): Future[UInt256] {.async.} = - convertEthersError: + convertEthersError("Failed to get slot's current collateral"): return await market.contract.currentCollateral(slotId) method getActiveSlot*(market: OnChainMarket, slotId: SlotId): Future[?Slot] {.async.} = - convertEthersError: + convertEthersError("Failed to get active slot"): try: return some await market.contract.getActiveSlot(slotId) except Marketplace_SlotIsFree: @@ -243,7 +244,7 @@ method fillSlot( proof: Groth16Proof, collateral: UInt256, ) {.async.} = - convertEthersError: + convertEthersError("Failed to fill slot"): logScope: requestId slotIndex @@ -254,7 +255,7 @@ method fillSlot( trace "fillSlot transaction completed" method freeSlot*(market: OnChainMarket, slotId: SlotId) {.async.} = - convertEthersError: + convertEthersError("Failed to free slot"): var freeSlot: Future[Confirmable] if rewardRecipient =? market.rewardRecipient: # If --reward-recipient specified, use it as the reward recipient, and use @@ -273,11 +274,11 @@ method freeSlot*(market: OnChainMarket, slotId: SlotId) {.async.} = discard await freeSlot.confirm(1) method withdrawFunds(market: OnChainMarket, requestId: RequestId) {.async.} = - convertEthersError: + convertEthersError("Failed to withdraw funds"): discard await market.contract.withdrawFunds(requestId).confirm(1) method isProofRequired*(market: OnChainMarket, id: SlotId): Future[bool] {.async.} = - convertEthersError: + convertEthersError("Failed to get proof requirement"): try: let overrides = CallOverrides(blockTag: some BlockTag.pending) return await market.contract.isProofRequired(id, overrides) @@ -285,7 +286,7 @@ method isProofRequired*(market: OnChainMarket, id: SlotId): Future[bool] {.async return false method willProofBeRequired*(market: OnChainMarket, id: SlotId): Future[bool] {.async.} = - convertEthersError: + convertEthersError("Failed to get future proof requirement"): try: let overrides = CallOverrides(blockTag: some BlockTag.pending) return await market.contract.willProofBeRequired(id, overrides) @@ -295,18 +296,18 @@ method willProofBeRequired*(market: OnChainMarket, id: SlotId): Future[bool] {.a method getChallenge*( market: OnChainMarket, id: SlotId ): Future[ProofChallenge] {.async.} = - convertEthersError: + convertEthersError("Failed to get proof challenge"): let overrides = CallOverrides(blockTag: some BlockTag.pending) return await market.contract.getChallenge(id, overrides) method submitProof*(market: OnChainMarket, id: SlotId, proof: Groth16Proof) {.async.} = - convertEthersError: + convertEthersError("Failed to submit proof"): discard await market.contract.submitProof(id, proof).confirm(1) method markProofAsMissing*( market: OnChainMarket, id: SlotId, period: Period ) {.async.} = - convertEthersError: + convertEthersError("Failed to mark proof as missing"): discard await market.contract.markProofAsMissing(id, period).confirm(1) method canProofBeMarkedAsMissing*( @@ -325,7 +326,7 @@ method canProofBeMarkedAsMissing*( method reserveSlot*( market: OnChainMarket, requestId: RequestId, slotIndex: uint64 ) {.async.} = - convertEthersError: + convertEthersError("Failed to reserve slot"): discard await market.contract .reserveSlot( requestId, @@ -338,7 +339,7 @@ method reserveSlot*( method canReserveSlot*( market: OnChainMarket, requestId: RequestId, slotIndex: uint64 ): Future[bool] {.async.} = - convertEthersError: + convertEthersError("Unable to determine if slot can be reserved"): return await market.contract.canReserveSlot(requestId, slotIndex) method subscribeRequests*( @@ -351,7 +352,7 @@ method subscribeRequests*( callback(event.requestId, event.ask, event.expiry) - convertEthersError: + convertEthersError("Failed to subscribe to StorageRequested events"): let subscription = await market.contract.subscribe(StorageRequested, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) @@ -365,7 +366,7 @@ method subscribeSlotFilled*( callback(event.requestId, event.slotIndex) - convertEthersError: + convertEthersError("Failed to subscribe to SlotFilled events"): let subscription = await market.contract.subscribe(SlotFilled, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) @@ -379,7 +380,7 @@ method subscribeSlotFilled*( if eventRequestId == requestId and eventSlotIndex == slotIndex: callback(requestId, slotIndex) - convertEthersError: + convertEthersError("Failed to subscribe to SlotFilled events"): return await market.subscribeSlotFilled(onSlotFilled) method subscribeSlotFreed*( @@ -392,7 +393,7 @@ method subscribeSlotFreed*( callback(event.requestId, event.slotIndex) - convertEthersError: + convertEthersError("Failed to subscribe to SlotFreed events"): let subscription = await market.contract.subscribe(SlotFreed, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) @@ -407,7 +408,7 @@ method subscribeSlotReservationsFull*( callback(event.requestId, event.slotIndex) - convertEthersError: + convertEthersError("Failed to subscribe to SlotReservationsFull events"): let subscription = await market.contract.subscribe(SlotReservationsFull, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) @@ -421,7 +422,7 @@ method subscribeFulfillment( callback(event.requestId) - convertEthersError: + convertEthersError("Failed to subscribe to RequestFulfilled events"): let subscription = await market.contract.subscribe(RequestFulfilled, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) @@ -436,7 +437,7 @@ method subscribeFulfillment( if event.requestId == requestId: callback(event.requestId) - convertEthersError: + convertEthersError("Failed to subscribe to RequestFulfilled events"): let subscription = await market.contract.subscribe(RequestFulfilled, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) @@ -450,7 +451,7 @@ method subscribeRequestCancelled*( callback(event.requestId) - convertEthersError: + convertEthersError("Failed to subscribe to RequestCancelled events"): let subscription = await market.contract.subscribe(RequestCancelled, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) @@ -465,7 +466,7 @@ method subscribeRequestCancelled*( if event.requestId == requestId: callback(event.requestId) - convertEthersError: + convertEthersError("Failed to subscribe to RequestCancelled events"): let subscription = await market.contract.subscribe(RequestCancelled, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) @@ -479,7 +480,7 @@ method subscribeRequestFailed*( callback(event.requestId) - convertEthersError: + convertEthersError("Failed to subscribe to RequestFailed events"): let subscription = await market.contract.subscribe(RequestFailed, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) @@ -494,7 +495,7 @@ method subscribeRequestFailed*( if event.requestId == requestId: callback(event.requestId) - convertEthersError: + convertEthersError("Failed to subscribe to RequestFailed events"): let subscription = await market.contract.subscribe(RequestFailed, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) @@ -508,7 +509,7 @@ method subscribeProofSubmission*( callback(event.id) - convertEthersError: + convertEthersError("Failed to subscribe to ProofSubmitted events"): let subscription = await market.contract.subscribe(ProofSubmitted, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) @@ -518,13 +519,13 @@ method unsubscribe*(subscription: OnChainMarketSubscription) {.async.} = method queryPastSlotFilledEvents*( market: OnChainMarket, fromBlock: BlockTag ): Future[seq[SlotFilled]] {.async.} = - convertEthersError: + convertEthersError("Failed to get past SlotFilled events from block"): return await market.contract.queryFilter(SlotFilled, fromBlock, BlockTag.latest) method queryPastSlotFilledEvents*( market: OnChainMarket, blocksAgo: int ): Future[seq[SlotFilled]] {.async.} = - convertEthersError: + convertEthersError("Failed to get past SlotFilled events"): let fromBlock = await market.contract.provider.pastBlockTag(blocksAgo) return await market.queryPastSlotFilledEvents(fromBlock) @@ -532,21 +533,21 @@ method queryPastSlotFilledEvents*( method queryPastSlotFilledEvents*( market: OnChainMarket, fromTime: SecondsSince1970 ): Future[seq[SlotFilled]] {.async.} = - convertEthersError: + convertEthersError("Failed to get past SlotFilled events from time"): let fromBlock = await market.contract.provider.blockNumberForEpoch(fromTime) return await market.queryPastSlotFilledEvents(BlockTag.init(fromBlock)) method queryPastStorageRequestedEvents*( market: OnChainMarket, fromBlock: BlockTag ): Future[seq[StorageRequested]] {.async.} = - convertEthersError: + convertEthersError("Failed to get past StorageRequested events from block"): return await market.contract.queryFilter(StorageRequested, fromBlock, BlockTag.latest) method queryPastStorageRequestedEvents*( market: OnChainMarket, blocksAgo: int ): Future[seq[StorageRequested]] {.async.} = - convertEthersError: + convertEthersError("Failed to get past StorageRequested events"): let fromBlock = await market.contract.provider.pastBlockTag(blocksAgo) return await market.queryPastStorageRequestedEvents(fromBlock) diff --git a/vendor/nim-ethers b/vendor/nim-ethers index d2b11a86..b505ef1a 160000 --- a/vendor/nim-ethers +++ b/vendor/nim-ethers @@ -1 +1 @@ -Subproject commit d2b11a865796a55296027f8ffba68398035ad435 +Subproject commit b505ef1ab889be8161bb1efb4908e3dfde5bc1c9