UNPKG

@gear-js/api

Version:

A JavaScript library that provides functionality to connect GEAR Component APIs.

296 lines (292 loc) 11.8 kB
'use strict'; var util = require('@polkadot/util'); const REPLY_CODE_LENGTH = 4; function padTo4Bytes(input) { const res = new Uint8Array(REPLY_CODE_LENGTH); res.set(input, 0); return res; } function checkAndGetCodeBytes(code, prevByteValue, prevBytePosition) { if (code.length < REPLY_CODE_LENGTH) { code = padTo4Bytes(code); } else if (code.length > REPLY_CODE_LENGTH) { code = code.slice(0, REPLY_CODE_LENGTH); } if (prevByteValue != null && code[prevBytePosition] !== prevByteValue) { throw new Error('Invalid byte sequence'); } return code; } exports.EReplyCode = void 0; (function (EReplyCode) { EReplyCode[EReplyCode["Success"] = 0] = "Success"; EReplyCode[EReplyCode["Error"] = 1] = "Error"; })(exports.EReplyCode || (exports.EReplyCode = {})); /** * # Reply Code decoder * @param codeBytes reply code * @param _specVersion spec version of the Gear runtime */ class ReplyCode { _specVersion; _bytes; constructor(codeBytes, _specVersion) { this._specVersion = _specVersion; this._bytes = checkAndGetCodeBytes(util.u8aToU8a(codeBytes)); if (this._bytes.length !== 4) { throw new Error('Invalid message reply code length'); } if (this._bytes[0] === 255) { throw new Error('Unsupported message reply code'); } } get isSuccess() { return this._bytes[0] === exports.EReplyCode.Success; } get isError() { return this._bytes[0] === exports.EReplyCode.Error; } get successReason() { return new SuccessReplyReason(this._bytes); } get errorReason() { return new ErrorReplyReason(this._bytes, this._specVersion); } get asString() { return this.isSuccess ? this.successReason.explanation : this.errorReason.explanation; } } exports.ESuccessReply = void 0; (function (ESuccessReply) { ESuccessReply[ESuccessReply["Auto"] = 0] = "Auto"; ESuccessReply[ESuccessReply["Manual"] = 1] = "Manual"; })(exports.ESuccessReply || (exports.ESuccessReply = {})); /** * # Success reply reason. */ class SuccessReplyReason { _bytes; constructor(bytes) { this._bytes = checkAndGetCodeBytes(bytes, exports.EReplyCode.Success, 0); } get explanation() { switch (this._bytes[1]) { case exports.ESuccessReply.Auto: { return 'Success reply was created by system automatically.'; } case exports.ESuccessReply.Manual: { return 'Success reply was created by actor manually.'; } default: { throw new Error('Unsupported reason of success reply.'); } } } get isAuto() { return this._bytes[1] === exports.ESuccessReply.Auto; } get isManual() { return this._bytes[1] === exports.ESuccessReply.Manual; } } var EErrorReplyReason; (function (EErrorReplyReason) { EErrorReplyReason[EErrorReplyReason["Execution"] = 0] = "Execution"; EErrorReplyReason[EErrorReplyReason["FailedToCreateProgram"] = 1] = "FailedToCreateProgram"; EErrorReplyReason[EErrorReplyReason["UnavailableActor"] = 2] = "UnavailableActor"; EErrorReplyReason[EErrorReplyReason["RemovedFromWaitlist"] = 3] = "RemovedFromWaitlist"; EErrorReplyReason[EErrorReplyReason["ReinstrumentationFailure"] = 4] = "ReinstrumentationFailure"; })(EErrorReplyReason || (EErrorReplyReason = {})); /** * # Error reply reason */ class ErrorReplyReason { _specVersion; _bytes; constructor(bytes, _specVersion) { this._specVersion = _specVersion; this._bytes = checkAndGetCodeBytes(bytes, exports.EReplyCode.Error, 0); } _throwUnsupported() { throw new Error('Unsupported reason of error reply.'); } get explanation() { switch (this._bytes[1]) { case EErrorReplyReason.Execution: { return `Error reply was created due to underlying execution error. Reason: ${this.executionReason.explanation}`; } case EErrorReplyReason.FailedToCreateProgram: { if (this._specVersion && this._specVersion < 1800) { return 'Failed to create program.'; } this._throwUnsupported(); break; } case EErrorReplyReason.UnavailableActor: { return `Destination actor is unavailable, so it can't process the message. Reason: ${this.unavailableActorReason.explanation}`; } case EErrorReplyReason.RemovedFromWaitlist: { return 'Message has died in Waitlist as out of rent one.'; } case EErrorReplyReason.ReinstrumentationFailure: { if (this._specVersion && this._specVersion < 1800) { return 'Reinstrumentation failed.'; } // falls through } default: { this._throwUnsupported(); break; } } // not reached — _throwUnsupported() always throws return this._bytes[1].toString(); } get isExecution() { return this._bytes[1] === EErrorReplyReason.Execution; } get executionReason() { return new ExecutionErrorReason(this._bytes); } /** This option is available only for spec versions before 1800 */ get isFailedToCreateProgram() { return this._specVersion && this._specVersion < 1800 && this._bytes[1] === EErrorReplyReason.FailedToCreateProgram; } get isUnavailableActor() { return this._bytes[1] === EErrorReplyReason.UnavailableActor; } get unavailableActorReason() { return new UnavailableActorErrorReason(this._bytes); } get isRemovedFromWaitlist() { return this._bytes[1] === EErrorReplyReason.RemovedFromWaitlist; } /** This option is available only for spec versions before 1800 */ get isReinstrumentationFailure() { return (this._specVersion && this._specVersion < 1800 && this._bytes[1] === EErrorReplyReason.ReinstrumentationFailure); } } exports.ESimpleExecutionError = void 0; (function (ESimpleExecutionError) { ESimpleExecutionError[ESimpleExecutionError["RanOutOfGas"] = 0] = "RanOutOfGas"; ESimpleExecutionError[ESimpleExecutionError["MemoryOverflow"] = 1] = "MemoryOverflow"; ESimpleExecutionError[ESimpleExecutionError["BackendError"] = 2] = "BackendError"; ESimpleExecutionError[ESimpleExecutionError["UserspacePanic"] = 3] = "UserspacePanic"; ESimpleExecutionError[ESimpleExecutionError["UnreachableInstruction"] = 4] = "UnreachableInstruction"; ESimpleExecutionError[ESimpleExecutionError["StackLimitExceeded"] = 5] = "StackLimitExceeded"; })(exports.ESimpleExecutionError || (exports.ESimpleExecutionError = {})); /** * # Execution error reason */ class ExecutionErrorReason { _bytes; constructor(bytes) { this._bytes = checkAndGetCodeBytes(bytes, EErrorReplyReason.Execution, 1); } get explanation() { switch (this._bytes[2]) { case exports.ESimpleExecutionError.RanOutOfGas: { return 'Message ran out of gas while executing.'; } case exports.ESimpleExecutionError.MemoryOverflow: { return 'Program has reached memory limit while executing.'; } case exports.ESimpleExecutionError.BackendError: { return "Execution failed with backend error that couldn't been caught."; } case exports.ESimpleExecutionError.UserspacePanic: { return 'Execution failed with userspace panic.'; } case exports.ESimpleExecutionError.UnreachableInstruction: { return 'Execution failed with `unreachable` instruction call.'; } case exports.ESimpleExecutionError.StackLimitExceeded: { return 'Program reached stack limit.'; } default: { throw new Error('Unsupported reason of execution error'); } } } get isRanOutOfGas() { return this._bytes[2] === exports.ESimpleExecutionError.RanOutOfGas; } get isMemoryOverflow() { return this._bytes[2] === exports.ESimpleExecutionError.MemoryOverflow; } get isBackendError() { return this._bytes[2] === exports.ESimpleExecutionError.BackendError; } get isUserspacePanic() { return this._bytes[2] === exports.ESimpleExecutionError.UserspacePanic; } get isUnreachableInstruction() { return this._bytes[2] === exports.ESimpleExecutionError.UnreachableInstruction; } get isStackLimitExceeded() { return this._bytes[2] === exports.ESimpleExecutionError.StackLimitExceeded; } } exports.ESimpleUnavailableActorError = void 0; (function (ESimpleUnavailableActorError) { ESimpleUnavailableActorError[ESimpleUnavailableActorError["ProgramExited"] = 0] = "ProgramExited"; ESimpleUnavailableActorError[ESimpleUnavailableActorError["InitializationFailure"] = 1] = "InitializationFailure"; ESimpleUnavailableActorError[ESimpleUnavailableActorError["Uninitialized"] = 2] = "Uninitialized"; ESimpleUnavailableActorError[ESimpleUnavailableActorError["ProgramNotCreated"] = 3] = "ProgramNotCreated"; ESimpleUnavailableActorError[ESimpleUnavailableActorError["ReinstrumentationFailure"] = 4] = "ReinstrumentationFailure"; })(exports.ESimpleUnavailableActorError || (exports.ESimpleUnavailableActorError = {})); class UnavailableActorErrorReason { _bytes; constructor(bytes) { this._bytes = checkAndGetCodeBytes(bytes, EErrorReplyReason.UnavailableActor, 1); } _throwUnsupported() { throw new Error('Unsupported reason of inactive actor error.'); } get explanation() { switch (this._bytes[2]) { case exports.ESimpleUnavailableActorError.ProgramExited: { return 'Program called `gr_exit` syscall.'; } case exports.ESimpleUnavailableActorError.InitializationFailure: { return 'Program was terminated due to failed initialization.'; } case exports.ESimpleUnavailableActorError.Uninitialized: { return 'Program is not initialized yet.'; } case exports.ESimpleUnavailableActorError.ProgramNotCreated: { return 'Program was not created.'; } case exports.ESimpleUnavailableActorError.ReinstrumentationFailure: { return 'Program re-instrumentation failed.'; } default: { this._throwUnsupported(); break; } } // not reached — _throwUnsupported() always throws return this._bytes[2].toString(); } get isProgramExited() { return this._bytes[2] === exports.ESimpleUnavailableActorError.ProgramExited; } get isInitializationFailure() { return this._bytes[2] === exports.ESimpleUnavailableActorError.InitializationFailure; } get isUninitialized() { return this._bytes[2] === exports.ESimpleUnavailableActorError.Uninitialized; } get isProgramNotCreated() { return this._bytes[2] === exports.ESimpleUnavailableActorError.ProgramNotCreated; } get isReinstrumentationFailure() { return this._bytes[2] === exports.ESimpleUnavailableActorError.ReinstrumentationFailure; } } exports.ErrorReplyReason = ErrorReplyReason; exports.ExecutionErrorReason = ExecutionErrorReason; exports.ReplyCode = ReplyCode; exports.SuccessReplyReason = SuccessReplyReason; exports.UnavailableActorErrorReason = UnavailableActorErrorReason;