From 1c31f95f7a1e4993ca0f1706002a975a0060dd88 Mon Sep 17 00:00:00 2001 From: Richard Moore Date: Mon, 30 Sep 2024 22:06:52 -0400 Subject: [PATCH] Allow CCIP-read to continue during low-level fetch failures (#4842). --- src.ts/_tests/test-providers-ccip.ts | 17 +++++++++++++++- src.ts/providers/abstract-provider.ts | 29 ++++++++++++++++++--------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src.ts/_tests/test-providers-ccip.ts b/src.ts/_tests/test-providers-ccip.ts index 49aba46f99..9a3e48628f 100644 --- a/src.ts/_tests/test-providers-ccip.ts +++ b/src.ts/_tests/test-providers-ccip.ts @@ -23,7 +23,7 @@ describe("Test CCIP execution", function() { assert.equal(result, keccak256(check), "response is equal"); } - const address = "0xaeaa06a37e6421ac63120d6daddee0ffa04b43e8"; + const address = "0xb66e9b20258712bfb9fd40acb13d7712ef149d6e"; const networkName = "sepolia"; const calldata = "0x1234"; @@ -176,6 +176,21 @@ describe("Test CCIP execution", function() { verify(address, calldata, result); }); + it("testGetDeadHostFallback passes if any URL returns correctly", async function() { + this.timeout(60000); + + const provider = connect(networkName); + + // testGetDeadHostFallback(bytes callData = "0x1234") + const tx = { + to: address, enableCcipRead: true, + data: "0x0324be5a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000021234000000000000000000000000000000000000000000000000000000000000" + } + + const result = await provider.call(tx); + verify(address, calldata, result); + }); + it("testPost passes under normal operation", async function() { this.timeout(60000); diff --git a/src.ts/providers/abstract-provider.ts b/src.ts/providers/abstract-provider.ts index 0a7448e249..0d75b435cc 100644 --- a/src.ts/providers/abstract-provider.ts +++ b/src.ts/providers/abstract-provider.ts @@ -42,7 +42,7 @@ import { import type { Addressable, AddressLike } from "../address/index.js"; import type { BigNumberish, BytesLike } from "../utils/index.js"; -import type { Listener } from "../utils/index.js"; +import type { FetchResponse, Listener } from "../utils/index.js"; import type { Networkish } from "./network.js"; import type { FetchUrlFeeDataNetworkPlugin } from "./plugins-network.js"; @@ -604,15 +604,26 @@ export class AbstractProvider implements Provider { let errorMessage = "unknown error"; - const resp = await request.send(); + // Fetch the resource... + let resp: FetchResponse; try { - const result = resp.bodyJson; - if (result.data) { - this.emit("debug", { action: "receiveCcipReadFetchResult", request, result }); - return result.data; - } - if (result.message) { errorMessage = result.message; } - this.emit("debug", { action: "receiveCcipReadFetchError", request, result }); + resp = await request.send(); + } catch (error: any) { + // ...low-level fetch error (missing host, bad SSL, etc.), + // so try next URL + errorMessages.push(error.message); + this.emit("debug", { action: "receiveCcipReadFetchError", request, result: { error } }); + continue; + } + + try { + const result = resp.bodyJson; + if (result.data) { + this.emit("debug", { action: "receiveCcipReadFetchResult", request, result }); + return result.data; + } + if (result.message) { errorMessage = result.message; } + this.emit("debug", { action: "receiveCcipReadFetchError", request, result }); } catch (error) { } // 4xx indicates the result is not present; stop