From 47b1645cfaaec53406d16bc310bc61e073e6b0e0 Mon Sep 17 00:00:00 2001 From: ruzell22 Date: Thu, 15 Aug 2024 13:27:28 +0800 Subject: [PATCH] fix(connector-besu): do not crash if ledger unreachable - send HTTP 503 Primary Changes --------------- 1. Yarn patch to web3-eth-acconts@1.6.1 so that it does not crash nodejs process Without the catch block, the rejection is an unhandled rejection that bubbles up to the top of the callstack where NodeJS itself catches it and then crashes the entire process. (used to be that it just logged a warning but since some of the newer versions it crashes which allows us to find these bugs in our code / library's code) 2. It is returning a 503 instead of a 500 3. Added a static retry-after header value of 5 seconds 4. Added test case in test-ledger which has run-transaction at the end that is expected to give error 503 when the backing ledger is unavailable Fixes: #3406 Co-authored-by: Peter Somogyvari Signed-off-by: ruzell22 Signed-off-by: Peter Somogyvari --- ...b3-eth-accounts-npm-1.6.1-c95f31ca81.patch | 13 ++ package.json | 1 + .../src/main/typescript/http/http-header.ts | 157 ++++++++++++++++++ .../src/main/typescript/public-api.ts | 2 + .../package.json | 6 +- .../src/main/json/openapi.tpl.json | 128 ++++++++++++++ ...bsocket-provider-abnormal-closure-error.ts | 38 +++++ .../web-services/run-transaction-endpoint.ts | 37 ++++- ...et-provider-abnormal-closure-error.test.ts | 41 +++++ .../run-transaction-endpoint.test.ts | 128 ++++++++++++++ yarn.lock | 77 ++++++--- 11 files changed, 597 insertions(+), 31 deletions(-) create mode 100644 .yarn/patches/web3-eth-accounts-npm-1.6.1-c95f31ca81.patch create mode 100644 packages/cactus-common/src/main/typescript/http/http-header.ts create mode 100644 packages/cactus-plugin-ledger-connector-besu/src/main/typescript/common/is-web3-websocket-provider-abnormal-closure-error.ts create mode 100644 packages/cactus-plugin-ledger-connector-besu/src/test/typescript/unit/common/is-web3-websocket-provider-abnormal-closure-error.test.ts create mode 100644 packages/cactus-test-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-validator-besu/run-transaction-endpoint.test.ts diff --git a/.yarn/patches/web3-eth-accounts-npm-1.6.1-c95f31ca81.patch b/.yarn/patches/web3-eth-accounts-npm-1.6.1-c95f31ca81.patch new file mode 100644 index 0000000000..984e901693 --- /dev/null +++ b/.yarn/patches/web3-eth-accounts-npm-1.6.1-c95f31ca81.patch @@ -0,0 +1,13 @@ +diff --git a/lib/index.js b/lib/index.js +index de2853c247b334e6b22cee42b3e597281c44efdc..787aecf6758228c092f1a3cd8097f64e76cc573d 100644 +--- a/lib/index.js ++++ b/lib/index.js +@@ -344,7 +344,7 @@ function _handleTxPricing(_this, tx) { + throw Error("Network doesn't support eip-1559"); + resolve({ gasPrice }); + } +- }); ++ }).catch((ex) => reject(ex)); + } + } + catch (error) { diff --git a/package.json b/package.json index c175dda0ba..1c75909393 100644 --- a/package.json +++ b/package.json @@ -118,6 +118,7 @@ "ws": ">=1.1.5", "xml2js": ">=0.5.0", "yargs-parser": ">=18.1.1", + "web3-eth-accounts@npm:1.6.1": "patch:web3-eth-accounts@npm%3A1.6.1#~/.yarn/patches/web3-eth-accounts-npm-1.6.1-c95f31ca81.patch", "zod": ">=3.22.3" }, "devDependencies": { diff --git a/packages/cactus-common/src/main/typescript/http/http-header.ts b/packages/cactus-common/src/main/typescript/http/http-header.ts new file mode 100644 index 0000000000..d1a77e1010 --- /dev/null +++ b/packages/cactus-common/src/main/typescript/http/http-header.ts @@ -0,0 +1,157 @@ +/** + * A list of well-known headers as published on Wikipedia. + * @see https://en.wikipedia.org/wiki/List_of_HTTP_header_fields + * + * TODO Finish documenting each enum item and make sure to also include + * the examples provided on the linked Wikipedia page above. The first + * few headers are documented this way but we need all of them like that. + * + * TODO Ensure that there are no typos in the header names. + */ +export enum HttpHeader { + // Standard request fields + + /** + * Acceptable instance-manipulations for the request. + * @example A-IM: feed + * @see https://datatracker.ietf.org/doc/html/rfc3229 + */ + A_IM = "A-IM", + /** + * Media type(s) that is/are acceptable for the response. See Content negotiation. + * @example Accept: text/html + * @see https://datatracker.ietf.org/doc/html/rfc9110 + */ + Accept = "Accept", + /** + * Character sets that are acceptable. + * @example Accept-Charset: utf-8 + * @see https://datatracker.ietf.org/doc/html/rfc9110 + */ + AcceptCharset = "Accept-Charset", + /** + * Acceptable version in time. + * @example Accept-Datetime: Thu, 31 May 2007 20:35:00 GMT + * @see https://datatracker.ietf.org/doc/html/rfc7089 + */ + AcceptDatetime = "Accept-Datetime", + AcceptEncoding = "Accept-Encoding", + AcceptLanguage = "Accept-Language", + AccessControlAllowOrigin = "Access-Control-Allow-Origin", + AccessControlAllowCredentials = "Access-Control-Allow-Credentials", + AccessControlExposeHeaders = "Access-Control-Expose-Headers", + AccessControlMaxAge = "Access-Control-Max-Age", + AccessControlAllowMethods = "Access-Control-Allow-Methods", + AccessControlAllowHeaders = "Access-Control-Allow-Headers", + Authorization = "Authorization", + CacheControl = "Cache-Control", + Connection = "Connection", + ContentDisposition = "Content-Disposition", + ContentEncoding = "Content-Encoding", + ContentLength = "Content-Length", + ContentLocation = "Content-Location", + ContentMD5 = "Content-MD5", + ContentType = "Content-Type", + Cookie = "Cookie", + Date = "Date", + Expect = "Expect", + Forwarded = "Forwarded", + From = "From", + Host = "Host", + IfMatch = "If-Match", + IfModifiedSince = "If-Modified-Since", + IfNoneMatch = "If-None-Match", + IfRange = "If-Range", + IfUnmodifiedSince = "If-Unmodified-Since", + MaxForwards = "Max-Forwards", + Origin = "Origin", + Pragma = "Pragma", + Prefer = "Prefer", + ProxyAuthorization = "Proxy-Authorization", + Range = "Range", + Referer = "Referer", + TE = "TE", + Trailer = "Trailer", + TransferEncoding = "Transfer-Encoding", + Upgrade = "Upgrade", + UserAgent = "User-Agent", + + // Common non-standard request fields + UpgradeInsecureRequests = "Upgrade-Insecure-Requests", + XRequestedWith = "X-Requested-With", + DNT = "DNT", + XForwardedFor = "X-Forwarded-For", + XForwardedHost = "X-Forwarded-Host", + XForwardedProto = "X-Forwarded-Proto", + FrontEndHttps = "Front-End-Https", + XHttpMethodOverride = "X-Http-Method-Override", + XAttDeviceId = "X-Att-DeviceId", + XWapProfile = "X-Wap-Profile", + ProxyConnection = "Proxy-Connection", + XUIDH = "X-UIDH", + XCsrfToken = "X-Csrf-Token", + XRequestId = "X-Request-ID", // Alternative X-Request-Id + CorrelationId = "X-Correlation-ID", // Alternative Correlation-ID + SaveData = "Save-Data", + SecGpc = "Sec-GPC", + + // Standard response fields + AcceptCH = "Accept-CH", + AcceptPatch = "Accept-Patch", + AltSvc = "Alt-Svc", + Age = "Age", + Allow = "Allow", + Expires = "Expires", + IM = "IM", + LastModified = "Last-Modified", + Link = "Link", + Location = "Location", + P3P = "P3P", + ProxyAuthenticate = "Proxy-Authenticate", + PublicKeyPins = "Public-Key-Pins", + /** + * f an entity is temporarily unavailable, this instructs the client + * to try again later. Value could be a specified period of time + * (in seconds) or a HTTP-date. + * + * There are two accepted formats when it comes to the values of the header: + * ```http + * Retry-After: + * Retry-After: + * ``` + * + * `` + * A date after which to retry. See the Date header for more details on the HTTP date format. + * + * `` + * A non-negative decimal integer indicating the seconds to delay after the response is received. + * + * @example Retry-After: 120 + * @example Retry-After: Fri, 07 Nov 2014 23:59:59 GMT + * + * @see https://datatracker.ietf.org/doc/html/rfc9110#section-10.2.3 + */ + RetryAfter = "Retry-After", + Server = "Server", + SetCookie = "Set-Cookie", + StrictTransportSecurity = "Strict-Transport-Security", + Tk = "Tk", + Vary = "Vary", + Via = "Via", // Same as request field + /** + * Indicates the authentication scheme that should be used to access the requested entity. + * @example WWW-Authenticate: Basic + * @see https://datatracker.ietf.org/doc/html/rfc9110 + */ + WWWAuthenticate = "WWW-Authenticate", + XFrameOptions = "X-Frame-Options", + + // Common non-standard response fields + ContentSecurityPolicy = "Content-Security-Policy", + ExpectCT = "Expect-CT", + NEL = "NEL", + PermissionsPolicy = "Permissions-Policy", + Refresh = "Refresh", + ReportTo = "Report-To", + Timing_Allow_Origin = "Timing-Allow-Origin", +} diff --git a/packages/cactus-common/src/main/typescript/public-api.ts b/packages/cactus-common/src/main/typescript/public-api.ts index 18e4ceb6c8..6dd0e177d0 100755 --- a/packages/cactus-common/src/main/typescript/public-api.ts +++ b/packages/cactus-common/src/main/typescript/public-api.ts @@ -47,3 +47,5 @@ export { } from "./http/express-http-verb-method-name"; export { isGrpcStatusObjectWithCode } from "./grpc/is-grpc-status-object-with-code"; + +export { HttpHeader } from "./http/http-header"; diff --git a/packages/cactus-plugin-ledger-connector-besu/package.json b/packages/cactus-plugin-ledger-connector-besu/package.json index 432992f5c7..025b74d2c1 100644 --- a/packages/cactus-plugin-ledger-connector-besu/package.json +++ b/packages/cactus-plugin-ledger-connector-besu/package.json @@ -80,7 +80,8 @@ "web3-eth": "1.6.1", "web3-eth-contract": "1.6.1", "web3-utils": "1.6.1", - "web3js-quorum": "22.4.0" + "web3js-quorum": "22.4.0", + "websocket-event-codes": "1.1.0" }, "devDependencies": { "@hyperledger/cactus-plugin-keychain-memory": "2.0.0", @@ -105,7 +106,8 @@ "tsx": "4.16.2", "uuid": "10.0.0", "web3-core": "1.6.1", - "web3-eth": "1.6.1" + "web3-eth": "1.6.1", + "web3-eth-accounts": "patch:web3-eth-accounts@npm%3A1.6.1#~/.yarn/patches/web3-eth-accounts-npm-1.6.1-c95f31ca81.patch" }, "engines": { "node": ">=18", diff --git a/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.tpl.json b/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.tpl.json index 545d518403..50f7b3457a 100644 --- a/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.tpl.json +++ b/packages/cactus-plugin-ledger-connector-besu/src/main/json/openapi.tpl.json @@ -1013,6 +1013,14 @@ "transactionInputData": {}, "callOutput": {} } + }, + "BackingLedgerUnavailableError": { + "properties": { + "message": { + "type": "string", + "example": "Backing Ledger Unavailable\n" + } + } } } }, @@ -1038,6 +1046,16 @@ } } } + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } @@ -1072,6 +1090,16 @@ } } } + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } @@ -1106,6 +1134,16 @@ } } } + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } @@ -1140,6 +1178,16 @@ } } } + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } @@ -1174,6 +1222,16 @@ } } } + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } @@ -1208,6 +1266,16 @@ } } } + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } @@ -1242,6 +1310,16 @@ } } } + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } @@ -1276,6 +1354,16 @@ } } } + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } @@ -1310,6 +1398,16 @@ } } } + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } @@ -1349,6 +1447,16 @@ }, "404": { "description": "Not able to find the corresponding tranaction from the transaction hash" + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } @@ -1374,6 +1482,16 @@ } } } + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } @@ -1408,6 +1526,16 @@ } } } + }, + "503": { + "description": "API is unable to reach the validator", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BackingLedgerUnavailableError" + } + } + } } } } diff --git a/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/common/is-web3-websocket-provider-abnormal-closure-error.ts b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/common/is-web3-websocket-provider-abnormal-closure-error.ts new file mode 100644 index 0000000000..82739d2ffe --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/common/is-web3-websocket-provider-abnormal-closure-error.ts @@ -0,0 +1,38 @@ +import { ABNORMAL_CLOSURE } from "websocket-event-codes"; + +export const WEB3_CONNECTION_NOT_OPEN_ON_SEND = "connection not open on send()"; + +/** + * Checks if an error was thrown due to the web3js websocket provider disconnecting. + * + * @param err - The error object to check. + * @returns `true` if the error is an instance of `Error`, has a `message` + * property indicating a websocket provider abnormal closure error. + * Otherwise, returns `false`. + * + * **Example:** + * ```typescript + * try { + * // ... code that might throw an error + * } catch (err: unknown) { + * if (isWeb3WebsocketProviderAbnormalClosureError(err)) { + * // Error is specifically due to websocket provider abnormal closure + * console.error("Websocket provider abnormal closure error:", err); + * } else { + * // Handle other types of errors + * console.error("Unknown error:", err); + * } + * } + * ``` + */ +export function isWeb3WebsocketProviderAbnormalClosureError( + err: unknown, +): err is Error & { code: typeof ABNORMAL_CLOSURE } { + if (!err) { + return false; + } + if (!(err instanceof Error)) { + return false; + } + return err.message.includes(WEB3_CONNECTION_NOT_OPEN_ON_SEND); +} diff --git a/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/web-services/run-transaction-endpoint.ts b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/web-services/run-transaction-endpoint.ts index 096be62d00..6387906209 100644 --- a/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/web-services/run-transaction-endpoint.ts +++ b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/web-services/run-transaction-endpoint.ts @@ -1,4 +1,5 @@ import { Express, Request, Response } from "express"; +import { HttpStatusCode } from "axios"; import { Logger, @@ -6,18 +7,23 @@ import { LogLevelDesc, LoggerProvider, IAsyncProvider, + HttpHeader, } from "@hyperledger/cactus-common"; import { IEndpointAuthzOptions, IExpressRequestHandler, IWebServiceEndpoint, } from "@hyperledger/cactus-core-api"; -import { registerWebServiceEndpoint } from "@hyperledger/cactus-core"; +import { + handleRestEndpointException, + registerWebServiceEndpoint, +} from "@hyperledger/cactus-core"; import { PluginLedgerConnectorBesu } from "../plugin-ledger-connector-besu"; import OAS from "../../json/openapi.json"; import { RunTransactionRequest } from "../generated/openapi/typescript-axios"; +import { isWeb3WebsocketProviderAbnormalClosureError } from "../common/is-web3-websocket-provider-abnormal-closure-error"; export interface IRunTransactionEndpointOptions { logLevel?: LogLevelDesc; @@ -82,19 +88,36 @@ export class RunTransactionEndpoint implements IWebServiceEndpoint { return this.handleRequest.bind(this); } + private handleLedgerNotAccessibleError(res: Response): void { + const fn = "handleLedgerNotAccessibleError()"; + this.log.debug( + "%s WebSocketProvider disconnected from ledger. Sending HttpStatusCode.ServiceUnavailable...", + fn, + ); + + res + .header(HttpHeader.RetryAfter, "5") + .status(HttpStatusCode.ServiceUnavailable) + .json({ + success: false, + error: "Could not establish connection to the backing ledger.", + }); + } + public async handleRequest(req: Request, res: Response): Promise { const reqTag = `${this.getVerbLowerCase()} - ${this.getPath()}`; + const { log } = this; this.log.debug(reqTag); const reqBody: RunTransactionRequest = req.body; try { const resBody = await this.options.connector.transact(reqBody); res.json({ success: true, data: resBody }); - } catch (ex) { - this.log.error(`Crash while serving ${reqTag}`, ex); - res.status(500).json({ - message: "Internal Server Error", - error: ex?.stack || ex?.message, - }); + } catch (ex: unknown) { + if (isWeb3WebsocketProviderAbnormalClosureError(ex)) { + return this.handleLedgerNotAccessibleError(res); + } + const errorMsg = `request handler fn crashed for: ${reqTag}`; + await handleRestEndpointException({ errorMsg, log, error: ex, res }); } } } diff --git a/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/unit/common/is-web3-websocket-provider-abnormal-closure-error.test.ts b/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/unit/common/is-web3-websocket-provider-abnormal-closure-error.test.ts new file mode 100644 index 0000000000..99182e239d --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/unit/common/is-web3-websocket-provider-abnormal-closure-error.test.ts @@ -0,0 +1,41 @@ +import "jest-extended"; + +import { isWeb3WebsocketProviderAbnormalClosureError } from "../../../../main/typescript/common/is-web3-websocket-provider-abnormal-closure-error"; +import { WEB3_CONNECTION_NOT_OPEN_ON_SEND } from "../../../../main/typescript/common/is-web3-websocket-provider-abnormal-closure-error"; + +describe("isWeb3WebsocketProviderAbnormalClosureError", () => { + it("should return false for non-error values", () => { + expect(isWeb3WebsocketProviderAbnormalClosureError(null)).toBe(false); + expect(isWeb3WebsocketProviderAbnormalClosureError(undefined)).toBe(false); + expect(isWeb3WebsocketProviderAbnormalClosureError(123)).toBe(false); + expect(isWeb3WebsocketProviderAbnormalClosureError("some string")).toBe( + false, + ); + expect(isWeb3WebsocketProviderAbnormalClosureError(Symbol("symbol"))).toBe( + false, + ); + }); + + it("should return false for error objects without code property", () => { + const errorWithoutCode = new Error("Some generic error"); + expect(isWeb3WebsocketProviderAbnormalClosureError(errorWithoutCode)).toBe( + false, + ); + }); + + it("should return false for error objects with incorrect code property", () => { + const errorWithIncorrectCode: Error = new Error("Some error"); + + (errorWithIncorrectCode as unknown as Record).code = + "some_other_code"; + + expect( + isWeb3WebsocketProviderAbnormalClosureError(errorWithIncorrectCode), + ).toBe(false); + }); + + it("it returns true when the correct error message is set", () => { + const err = new Error(WEB3_CONNECTION_NOT_OPEN_ON_SEND); + expect(isWeb3WebsocketProviderAbnormalClosureError(err)).toBeTrue(); + }); +}); diff --git a/packages/cactus-test-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-validator-besu/run-transaction-endpoint.test.ts b/packages/cactus-test-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-validator-besu/run-transaction-endpoint.test.ts new file mode 100644 index 0000000000..6a555f0265 --- /dev/null +++ b/packages/cactus-test-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-validator-besu/run-transaction-endpoint.test.ts @@ -0,0 +1,128 @@ +import "jest-extended"; +import { v4 as uuidv4 } from "uuid"; +import { createServer } from "http"; +import { AddressInfo } from "net"; + +import { + ApiServer, + AuthorizationProtocol, + ConfigService, +} from "@hyperledger/cactus-cmd-api-server"; + +import { + BesuTestLedger, + pruneDockerAllIfGithubAction, +} from "@hyperledger/cactus-test-tooling"; + +import { + BesuApiClientOptions, + BesuApiClient, + IPluginLedgerConnectorBesuOptions, + PluginLedgerConnectorBesu, + Web3SigningCredentialType, + ReceiptType, + RunTransactionRequest, +} from "@hyperledger/cactus-plugin-ledger-connector-besu"; + +import { PluginRegistry } from "@hyperledger/cactus-core"; + +const testCase = "Test runTransactionV1 endpoint"; +const fRun = "runTransactionV1"; +const cLedgerUnavailable = "backing ledger unavailable"; +const logLevel = "TRACE"; +let apiServer: ApiServer; +let api: BesuApiClient; +let besuTestLedger: BesuTestLedger; + +describe(testCase, () => { + beforeAll(async () => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await expect(pruning).resolves.toBeTruthy(); + + // Initialize Besu test ledger + const containerImageVersion = "2021-08-24--feat-1244"; + const containerImageName = "ghcr.io/hyperledger/cactus-besu-21-1-6-all-in-one"; + besuTestLedger = new BesuTestLedger({ containerImageName, containerImageVersion }); + await besuTestLedger.start(); + + // Setup HTTP server and ApiServer + const httpServer = createServer(); + await new Promise((resolve, reject) => { + httpServer.once("error", reject); + httpServer.once("listening", resolve); + httpServer.listen(0, "127.0.0.1"); + }); + const addressInfo = httpServer.address() as AddressInfo; + + const rpcApiHttpHost = await besuTestLedger.getRpcApiHttpHost(); + const rpcApiWsHost = await besuTestLedger.getRpcApiWsHost(); + + const pluginRegistry = new PluginRegistry(); + const options: IPluginLedgerConnectorBesuOptions = { + instanceId: uuidv4(), + rpcApiHttpHost, + rpcApiWsHost, + pluginRegistry, + logLevel, + }; + const pluginValidatorBesu = new PluginLedgerConnectorBesu(options); + pluginRegistry.add(pluginValidatorBesu); + + const configService = new ConfigService(); + const apiServerOptions = await configService.newExampleConfig(); + apiServerOptions.authorizationProtocol = AuthorizationProtocol.NONE; + apiServerOptions.configFile = ""; + apiServerOptions.apiCorsDomainCsv = "*"; + apiServerOptions.apiPort = addressInfo.port; + apiServerOptions.cockpitPort = 0; + apiServerOptions.apiTlsEnabled = false; + + const config = await configService.newExampleConfigConvict(apiServerOptions); + apiServer = new ApiServer({ + httpServerApi: httpServer, + config: config.getProperties(), + pluginRegistry, + }); + await apiServer.start(); + + const configuration = new BesuApiClientOptions({ basePath: `http://${addressInfo.address}:${addressInfo.port}` }); + api = new BesuApiClient(configuration); + }); + + afterAll(async () => { + await apiServer.shutdown(); + }); + + test(`${testCase} - ${fRun} - ${cLedgerUnavailable}`, async () => { + const testEthAccount1 = await besuTestLedger.createEthTestAccount(); + const testEthAccount2 = await besuTestLedger.createEthTestAccount(); + const parameters = { + web3SigningCredential: { + ethAccount: testEthAccount1.address, + secret: testEthAccount1.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + transactionConfig: { + from: testEthAccount1.address, + to: testEthAccount2.address, + value: 10e7, + gas: 1000000, + }, + consistencyStrategy: { + blockConfirmations: 0, + receiptType: ReceiptType.NodeTxPoolAck, + timeoutMs: 5000, + }, + }; + + await besuTestLedger.stop(); + await besuTestLedger.destroy(); + + try { + const res = await api.runTransactionV1(parameters as RunTransactionRequest); + expect(res).toBeTruthy(); + } catch (error) { + expect(error.response?.status).toEqual(503); + } + }); +}); diff --git a/yarn.lock b/yarn.lock index a85c6ec45f..966ba5b903 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10300,9 +10300,11 @@ __metadata: web3: "npm:1.6.1" web3-core: "npm:1.6.1" web3-eth: "npm:1.6.1" + web3-eth-accounts: "patch:web3-eth-accounts@npm%3A1.6.1#~/.yarn/patches/web3-eth-accounts-npm-1.6.1-c95f31ca81.patch" web3-eth-contract: "npm:1.6.1" web3-utils: "npm:1.6.1" web3js-quorum: "npm:22.4.0" + websocket-event-codes: "npm:1.1.0" languageName: unknown linkType: soft @@ -28621,7 +28623,7 @@ __metadata: languageName: node linkType: hard -"ethereumjs-util@npm:^7.0.10, ethereumjs-util@npm:^7.1.0, ethereumjs-util@npm:^7.1.1, ethereumjs-util@npm:^7.1.4": +"ethereumjs-util@npm:^7.0.10, ethereumjs-util@npm:^7.1.0, ethereumjs-util@npm:^7.1.4": version: 7.1.4 resolution: "ethereumjs-util@npm:7.1.4" dependencies: @@ -28634,7 +28636,7 @@ __metadata: languageName: node linkType: hard -"ethereumjs-util@npm:^7.0.2, ethereumjs-util@npm:^7.1.2, ethereumjs-util@npm:^7.1.5": +"ethereumjs-util@npm:^7.0.2, ethereumjs-util@npm:^7.1.1, ethereumjs-util@npm:^7.1.2, ethereumjs-util@npm:^7.1.5": version: 7.1.5 resolution: "ethereumjs-util@npm:7.1.5" dependencies: @@ -53873,7 +53875,7 @@ __metadata: languageName: node linkType: hard -"web3-eth-accounts@npm:4.1.1, web3-eth-accounts@npm:^4.1.1": +"web3-eth-accounts@npm:4.1.1": version: 4.1.1 resolution: "web3-eth-accounts@npm:4.1.1" dependencies: @@ -53888,33 +53890,37 @@ __metadata: languageName: node linkType: hard -"web3-eth-accounts@npm:^4.0.3, web3-eth-accounts@npm:^4.0.5": - version: 4.0.5 - resolution: "web3-eth-accounts@npm:4.0.5" +"web3-eth-accounts@npm:^4.0.3, web3-eth-accounts@npm:^4.0.5, web3-eth-accounts@npm:^4.1.0, web3-eth-accounts@npm:^4.1.1": + version: 4.1.3 + resolution: "web3-eth-accounts@npm:4.1.3" dependencies: "@ethereumjs/rlp": "npm:^4.0.1" crc-32: "npm:^1.2.2" ethereum-cryptography: "npm:^2.0.0" - web3-errors: "npm:^1.1.1" - web3-types: "npm:^1.1.1" - web3-utils: "npm:^4.0.5" - web3-validator: "npm:^2.0.1" - checksum: 10/37e9e2d909544e3d9b8b9bf3168365cd068653b18880cb65835c9b2a3acefc885ecb18de52ead56f7a3663b33a6bb58d19e4e9fc21f2618cd9cb262a355a7dc1 + web3-errors: "npm:^1.2.0" + web3-types: "npm:^1.7.0" + web3-utils: "npm:^4.3.1" + web3-validator: "npm:^2.0.6" + checksum: 10/c5d4aa7b82517372666833e1752ffb2e768932833284de9388d710399dbdb609b129af76e4f658a0679ae18190b627e2b2331ad616ab3109c741dcd75a9e9524 languageName: node linkType: hard -"web3-eth-accounts@npm:^4.1.0": - version: 4.1.0 - resolution: "web3-eth-accounts@npm:4.1.0" +"web3-eth-accounts@patch:web3-eth-accounts@npm%3A1.6.1#~/.yarn/patches/web3-eth-accounts-npm-1.6.1-c95f31ca81.patch": + version: 1.6.1 + resolution: "web3-eth-accounts@patch:web3-eth-accounts@npm%3A1.6.1#~/.yarn/patches/web3-eth-accounts-npm-1.6.1-c95f31ca81.patch::version=1.6.1&hash=f41816" dependencies: - "@ethereumjs/rlp": "npm:^4.0.1" - crc-32: "npm:^1.2.2" - ethereum-cryptography: "npm:^2.0.0" - web3-errors: "npm:^1.1.3" - web3-types: "npm:^1.3.0" - web3-utils: "npm:^4.0.7" - web3-validator: "npm:^2.0.3" - checksum: 10/2048b3d1211593a44921a7cf200a2a407d82f832eae5751aa3b193012f4c084038814878c9423988636435f9b41967769a854ab643fb7d3cda8d898ad070be26 + "@ethereumjs/common": "npm:^2.5.0" + "@ethereumjs/tx": "npm:^3.3.2" + crypto-browserify: "npm:3.12.0" + eth-lib: "npm:0.2.8" + ethereumjs-util: "npm:^7.0.10" + scrypt-js: "npm:^3.0.1" + uuid: "npm:3.3.2" + web3-core: "npm:1.6.1" + web3-core-helpers: "npm:1.6.1" + web3-core-method: "npm:1.6.1" + web3-utils: "npm:1.6.1" + checksum: 10/5446cb368d4a6f72b85c7d0f7f1a894ae1090749d660ee0289d82b5e77f10ff885d36f2cc857ddb2c6e1a84b8081bddec3203ecc390bba43d39919e0e066502b languageName: node linkType: hard @@ -54942,6 +54948,13 @@ __metadata: languageName: node linkType: hard +"web3-types@npm:^1.7.0": + version: 1.7.0 + resolution: "web3-types@npm:1.7.0" + checksum: 10/fcd5d7a9a94579fcd01fa86dfa70e6afb269f66a7ce60e6786849e64ff6e4a107f1c25cb2784343a48952ac36d4bf3093a73b75de6ebcc971308e6b44abb211f + languageName: node + linkType: hard + "web3-utils@npm:1.10.0": version: 1.10.0 resolution: "web3-utils@npm:1.10.0" @@ -55060,6 +55073,19 @@ __metadata: languageName: node linkType: hard +"web3-utils@npm:^4.3.1": + version: 4.3.1 + resolution: "web3-utils@npm:4.3.1" + dependencies: + ethereum-cryptography: "npm:^2.0.0" + eventemitter3: "npm:^5.0.1" + web3-errors: "npm:^1.2.0" + web3-types: "npm:^1.7.0" + web3-validator: "npm:^2.0.6" + checksum: 10/88e39a6d43b756e965226b25ddc54855f26a7c13f6240b99fb521e1bae35a20a24f637f09fd0f4ef5d3f5a9e46b7f843bb5fd7ac2c9f99cfe18bb71817390f6e + languageName: node + linkType: hard + "web3-validator@npm:2.0.2": version: 2.0.2 resolution: "web3-validator@npm:2.0.2" @@ -55666,6 +55692,13 @@ __metadata: languageName: node linkType: hard +"websocket-event-codes@npm:1.1.0": + version: 1.1.0 + resolution: "websocket-event-codes@npm:1.1.0" + checksum: 10/97db632273f3de620856f984f7d17672c7c221ca80af3d2790681947f029bfc3128dd16c9ddc82e62251e0537eb0d4567ce4a5609776c09bf3996e1fc21a9332 + languageName: node + linkType: hard + "websocket-extensions@npm:>=0.1.1": version: 0.1.4 resolution: "websocket-extensions@npm:0.1.4"