UNPKG

@gear-js/api

Version:

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

249 lines (246 loc) 9.05 kB
import { u8aToU8a } from '@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; } /** * # 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(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] === 0 /* EReplyCode.Success */; } get isError() { return this._bytes[0] === 1 /* 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; } } /** * # Success reply reason. */ class SuccessReplyReason { _bytes; constructor(bytes) { this._bytes = checkAndGetCodeBytes(bytes, 0 /* EReplyCode.Success */, 0); } get explanation() { switch (this._bytes[1]) { case 0 /* ESuccessReply.Auto */: { return 'Success reply was created by system automatically.'; } case 1 /* 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] === 0 /* ESuccessReply.Auto */; } get isManual() { return this._bytes[1] === 1 /* ESuccessReply.Manual */; } } /** * # Error reply reason */ class ErrorReplyReason { _specVersion; _bytes; constructor(bytes, _specVersion) { this._specVersion = _specVersion; this._bytes = checkAndGetCodeBytes(bytes, 1 /* EReplyCode.Error */, 0); } _throwUnsupported() { throw new Error('Unsupported reason of error reply.'); } get explanation() { switch (this._bytes[1]) { case 0 /* EErrorReplyReason.Execution */: { return `Error reply was created due to underlying execution error. Reason: ${this.executionReason.explanation}`; } case 1 /* EErrorReplyReason.FailedToCreateProgram */: { if (this._specVersion && this._specVersion < 1800) { return 'Failed to create program.'; } this._throwUnsupported(); break; } case 2 /* EErrorReplyReason.UnavailableActor */: { return `Destination actor is unavailable, so it can't process the message. Reason: ${this.unavailableActorReason.explanation}`; } case 3 /* EErrorReplyReason.RemovedFromWaitlist */: { return 'Message has died in Waitlist as out of rent one.'; } case 4 /* EErrorReplyReason.ReinstrumentationFailure */: { if (this._specVersion && this._specVersion < 1800) { return 'Reinstrumentation failed.'; } } // falls through default: { this._throwUnsupported(); } } } get isExecution() { return this._bytes[1] === 0 /* 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] === 1 /* EErrorReplyReason.FailedToCreateProgram */; } get isUnavailableActor() { return this._bytes[1] === 2 /* EErrorReplyReason.UnavailableActor */; } get unavailableActorReason() { return new UnavailableActorErrorReason(this._bytes); } get isRemovedFromWaitlist() { return this._bytes[1] === 3 /* EErrorReplyReason.RemovedFromWaitlist */; } /** This option is available only for spec versions before 1800 */ get isReinstrumentationFailure() { return (this._specVersion && this._specVersion < 1800 && this._bytes[1] === 4 /* EErrorReplyReason.ReinstrumentationFailure */); } } /** * # Execution error reason */ class ExecutionErrorReason { _bytes; constructor(bytes) { this._bytes = checkAndGetCodeBytes(bytes, 0 /* EErrorReplyReason.Execution */, 1); } get explanation() { switch (this._bytes[2]) { case 0 /* ESimpleExecutionError.RanOutOfGas */: { return 'Message ran out of gas while executing.'; } case 1 /* ESimpleExecutionError.MemoryOverflow */: { return 'Program has reached memory limit while executing.'; } case 2 /* ESimpleExecutionError.BackendError */: { return "Execution failed with backend error that couldn't been caught."; } case 3 /* ESimpleExecutionError.UserspacePanic */: { return 'Execution failed with userspace panic.'; } case 4 /* ESimpleExecutionError.UnreachableInstruction */: { return 'Execution failed with `unreachable` instruction call.'; } case 5 /* ESimpleExecutionError.StackLimitExceeded */: { return 'Program reached stack limit.'; } default: { throw new Error('Unsupported reason of execution error'); } } } get isRanOutOfGas() { return this._bytes[2] == 0 /* ESimpleExecutionError.RanOutOfGas */; } get isMemoryOverflow() { return this._bytes[2] == 1 /* ESimpleExecutionError.MemoryOverflow */; } get isBackendError() { return this._bytes[2] == 2 /* ESimpleExecutionError.BackendError */; } get isUserspacePanic() { return this._bytes[2] == 3 /* ESimpleExecutionError.UserspacePanic */; } get isUnreachableInstruction() { return this._bytes[2] == 4 /* ESimpleExecutionError.UnreachableInstruction */; } get isStackLimitExceeded() { return this._bytes[2] == 5 /* ESimpleExecutionError.StackLimitExceeded */; } } class UnavailableActorErrorReason { _bytes; constructor(bytes) { this._bytes = checkAndGetCodeBytes(bytes, 2 /* EErrorReplyReason.UnavailableActor */, 1); } _throwUnsupported() { throw new Error('Unsupported reason of inactive actor error.'); } get explanation() { switch (this._bytes[2]) { case 0 /* ESimpleUnavailableActorError.ProgramExited */: { return 'Program called `gr_exit` syscall.'; } case 1 /* ESimpleUnavailableActorError.InitializationFailure */: { return 'Program was terminated due to failed initialization.'; } case 2 /* ESimpleUnavailableActorError.Uninitialized */: { return 'Program is not initialized yet.'; } case 3 /* ESimpleUnavailableActorError.ProgramNotCreated */: { return 'Program was not created.'; } case 4 /* ESimpleUnavailableActorError.ReinstrumentationFailure */: { return 'Program re-instrumentation failed.'; } default: { this._throwUnsupported(); } } } get isProgramExited() { return this._bytes[2] == 0 /* ESimpleUnavailableActorError.ProgramExited */; } get isInitializationFailure() { return this._bytes[2] == 1 /* ESimpleUnavailableActorError.InitializationFailure */; } get isUninitialized() { return this._bytes[2] == 2 /* ESimpleUnavailableActorError.Uninitialized */; } get isProgramNotCreated() { return this._bytes[2] == 3 /* ESimpleUnavailableActorError.ProgramNotCreated */; } get isReinstrumentationFailure() { return this._bytes[2] == 4 /* ESimpleUnavailableActorError.ReinstrumentationFailure */; } } export { ErrorReplyReason, ExecutionErrorReason, ReplyCode, SuccessReplyReason, UnavailableActorErrorReason };