@gear-js/api
Version:
A JavaScript library that provides functionality to connect GEAR Component APIs.
249 lines (246 loc) • 9.05 kB
JavaScript
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 };