Skip to content
Snippets Groups Projects
Commit bfa18af3 authored by Mateusz Tyszczak's avatar Mateusz Tyszczak :scroll: Committed by Bartek Wrona
Browse files

Re-Pack all WASM calls into try/catch blocks to prevent large stacktraces...

Re-Pack all WASM calls into try/catch blocks to prevent large stacktraces overflowing console buffers
parent dedd9c6a
No related branches found
No related tags found
1 merge request!213Re-Pack all WASM calls into try/catch blocks to prevent large stacktraces overflowing console buffers
import type { IWaxBaseInterface, IWaxOptions } from "../interfaces.js";
// @ts-expect-error ts(6133) Type WaxError is used in JSDoc
import type { WaxError } from "../errors";
import { WaxBaseApi } from "./base_api.js";
import MainModuleFunction from "../wax_module.js";
import { safeAsyncWasmCall } from "./util/wasm_errors.js";
export const DEFAULT_WAX_OPTIONS: IWaxOptions = {
chainId: "beeab0de00000000000000000000000000000000000000000000000000000000"
......@@ -20,7 +18,7 @@ export const DEFAULT_WAX_OPTIONS: IWaxOptions = {
* @throws {WaxError} on any Wax API-related error
*/
export const createWaxFoundation = async(options: Partial<IWaxOptions> = {}): Promise<IWaxBaseInterface> => {
const waxProvider = await MainModuleFunction();
const waxProvider = await safeAsyncWasmCall(() => MainModuleFunction());
const apiOptions: IWaxOptions = { ...DEFAULT_WAX_OPTIONS, ...options };
......
......@@ -4,6 +4,7 @@ import type { json_price, MainModule, proto_protocol, result, witness_set_proper
import type { ApiTransaction, NaiAsset } from "./api";
import { WaxError } from '../errors.js';
import { safeWasmCall } from "./util/wasm_errors.js";
import { Transaction } from "./transaction.js";
import Long from "long";
......@@ -67,7 +68,7 @@ export class WaxBaseApi implements IWaxBaseInterface {
const actualHbdAmountToGet = this.createAssetWithRequiredSymbol(EAssetName.HBD, hbdAmountToGet);
return this.proto.cpp_estimate_hive_collateral(currentMedianHistory, currentMinHistory, actualHbdAmountToGet) as NaiAsset;
return safeWasmCall(() => this.proto.cpp_estimate_hive_collateral(currentMedianHistory, currentMinHistory, actualHbdAmountToGet) as NaiAsset);
}
public deserializeWitnessProps(serializedWitnessProps: Array<[string, string]>): witness_set_properties_data {
......@@ -75,11 +76,11 @@ export class WaxBaseApi implements IWaxBaseInterface {
for (const [key, serializedValue] of serializedWitnessProps)
map.set(key, serializedValue);
return this.proto.cpp_deserialize_witness_set_properties(map);
return safeWasmCall(() => this.proto.cpp_deserialize_witness_set_properties(map))
}
public serializeWitnessProps(witnessProps: witness_set_properties_data): Record<string, string> {
const propsSerialized = this.proto.cpp_serialize_witness_set_properties(witnessProps);
const propsSerialized = safeWasmCall(() => this.proto.cpp_serialize_witness_set_properties(witnessProps));
const propsKeys = propsSerialized.keys();
const keys: string[] = [];
......@@ -131,19 +132,19 @@ export class WaxBaseApi implements IWaxBaseInterface {
public hiveSatoshis(amount: TNaiAssetConvertible): NaiAsset {
const long = Long.fromString(amount.toString());
return this.proto.cpp_hive(long.low, long.high) as NaiAsset;
return safeWasmCall(() => this.proto.cpp_hive(long.low, long.high) as NaiAsset);
}
public hbdSatoshis(amount: TNaiAssetConvertible): NaiAsset {
const long = Long.fromString(amount.toString());
return this.proto.cpp_hbd(long.low, long.high) as NaiAsset;
return safeWasmCall(() => this.proto.cpp_hbd(long.low, long.high) as NaiAsset);
}
public vestsSatoshis(amount: TNaiAssetConvertible): NaiAsset {
const long = Long.fromString(amount.toString());
return this.proto.cpp_vests(long.low, long.high) as NaiAsset;
return safeWasmCall(() => this.proto.cpp_vests(long.low, long.high) as NaiAsset);
}
public vestsToHp(vests: TNaiAssetSource, totalVestingFundHive: TNaiAssetSource, totalVestingShares: TNaiAssetSource): NaiAsset {
......@@ -151,7 +152,7 @@ export class WaxBaseApi implements IWaxBaseInterface {
const totalVestingFundHiveAsset = this.createAssetWithRequiredSymbol(EAssetName.HIVE, totalVestingFundHive);
const totalVestingSharesAsset = this.createAssetWithRequiredSymbol(EAssetName.VESTS, totalVestingShares);
return this.proto.cpp_vests_to_hp(vestsAsset, totalVestingFundHiveAsset, totalVestingSharesAsset) as NaiAsset;
return safeWasmCall(() => this.proto.cpp_vests_to_hp(vestsAsset, totalVestingFundHiveAsset, totalVestingSharesAsset) as NaiAsset);
}
public hbdToHive(hbd: TNaiAssetSource, base: TNaiAssetSource, quote: TNaiAssetSource): NaiAsset {
......@@ -159,7 +160,7 @@ export class WaxBaseApi implements IWaxBaseInterface {
const baseAsset = this.createAssetWithRequiredSymbol(EAssetName.HBD, base as NaiAsset);
const quoteAsset = this.createAssetWithRequiredSymbol(EAssetName.HIVE, quote as NaiAsset);
return this.proto.cpp_hbd_to_hive(hbdAsset, baseAsset, quoteAsset) as NaiAsset;
return safeWasmCall(() => this.proto.cpp_hbd_to_hive(hbdAsset, baseAsset, quoteAsset) as NaiAsset);
}
public hiveToHbd(amount: TNaiAssetSource, base: TNaiAssetSource, quote: TNaiAssetSource): NaiAsset {
......@@ -167,7 +168,7 @@ export class WaxBaseApi implements IWaxBaseInterface {
const baseAsset = this.createAssetWithRequiredSymbol(EAssetName.HBD, base);
const quoteAsset = this.createAssetWithRequiredSymbol(EAssetName.HIVE, quote);
return this.proto.cpp_hive_to_hbd(amountAsset, baseAsset, quoteAsset) as NaiAsset;
return safeWasmCall(() => this.proto.cpp_hive_to_hbd(amountAsset, baseAsset, quoteAsset) as NaiAsset);
}
public extract(res: result): string {
......@@ -181,7 +182,7 @@ export class WaxBaseApi implements IWaxBaseInterface {
public readonly wax: MainModule,
public readonly chainId: string
) {
this.proto = new wax.proto_protocol();
this.proto = safeWasmCall(() => new wax.proto_protocol());
this.ASSETS = {
[EAssetName.HBD]: this.hbdSatoshis(0),
[EAssetName.HIVE]: this.hiveSatoshis(0),
......@@ -215,8 +216,8 @@ export class WaxBaseApi implements IWaxBaseInterface {
}
public getAsset(nai: NaiAsset): IHiveAssetData {
const symbol = this.proto.cpp_asset_symbol(nai);
const amount = this.proto.cpp_asset_value(nai);
const symbol = safeWasmCall(() => this.proto.cpp_asset_symbol(nai));
const amount = safeWasmCall(() => this.proto.cpp_asset_value(nai));
return {
symbol,
......@@ -225,7 +226,7 @@ export class WaxBaseApi implements IWaxBaseInterface {
}
public get addressPrefix(): string {
return this.proto.cpp_get_address_prefix() as string;
return safeWasmCall(() => this.proto.cpp_get_address_prefix() as string);
}
public getVersion(): string {
......@@ -233,21 +234,23 @@ export class WaxBaseApi implements IWaxBaseInterface {
}
public getPublicKeyFromSignature(sigDigest: THexString, signature: THexString): THexString {
return this.extract(this.proto.cpp_get_public_key_from_signature(sigDigest, signature));
const publicKey = safeWasmCall(() => this.proto.cpp_get_public_key_from_signature(sigDigest, signature));
return this.extract(publicKey);
}
public encrypt(wallet: IBeekeeperUnlockedWallet, content: string, mainEncryptionKey: TPublicKey, otherEncryptionKey?: TPublicKey, nonce?: number): string {
const encrypted = wallet.encryptData(content, mainEncryptionKey, otherEncryptionKey, nonce);
return this.proto.cpp_crypto_memo_dump_string({
return safeWasmCall(() => this.proto.cpp_crypto_memo_dump_string({
content: encrypted,
from: mainEncryptionKey,
to: otherEncryptionKey ?? mainEncryptionKey
});
}));
}
public decrypt(wallet: IBeekeeperUnlockedWallet, encrypted: string): string {
const data = this.proto.cpp_crypto_memo_from_string(encrypted);
const data = safeWasmCall(() => this.proto.cpp_crypto_memo_from_string(encrypted));
return wallet.decryptData(data.content as string, data.from as string, data.to as string);
}
......@@ -268,45 +271,43 @@ export class WaxBaseApi implements IWaxBaseInterface {
}
public calculateCurrentManabarValue(now: number, maxManaLH: number | string | Long, currentManaLH: number | string | Long, lastUpdateTime: number): IManabarData {
if(typeof maxManaLH !== "object")
maxManaLH = Long.fromValue(maxManaLH, true);
if(typeof currentManaLH !== "object")
currentManaLH = Long.fromValue(currentManaLH, true);
const maxMana: Long = typeof maxManaLH === "object" ? maxManaLH : Long.fromValue(maxManaLH, true);
const currentMana: Long = typeof currentManaLH === "object" ? currentManaLH : Long.fromValue(currentManaLH, true);
if(maxManaLH.equals(0))
if(maxMana.equals(0))
return {
max: maxManaLH,
max: maxMana,
current: Long.ZERO,
percent: 100
};
const current = Long.fromString(this.extract(this.proto.cpp_calculate_current_manabar_value(now, maxManaLH.low, maxManaLH.high, currentManaLH.low, currentManaLH.high, lastUpdateTime)), true);
const manabarValue = safeWasmCall(() => this.proto.cpp_calculate_current_manabar_value(now, maxMana.low, maxMana.high, currentMana.low, currentMana.high, lastUpdateTime));
const current = Long.fromString(this.extract(manabarValue), true);
const percent = this.calculateManabarPercent(current, maxManaLH);
const percent = this.calculateManabarPercent(current, maxMana);
return {
max: maxManaLH,
max: maxMana,
current,
percent
};
}
public calculateManabarFullRegenerationTime(now: number, maxManaLH: number | string | Long, currentManaLH: number | string | Long, lastUpdateTime: number): number {
if(typeof maxManaLH !== "object")
maxManaLH = Long.fromString(maxManaLH.toString(), true);
const maxMana: Long = typeof maxManaLH === "object" ? maxManaLH : Long.fromValue(maxManaLH, true);
const currentMana: Long = typeof currentManaLH === "object" ? currentManaLH : Long.fromValue(currentManaLH, true);
if(typeof currentManaLH !== "object")
currentManaLH = Long.fromString(currentManaLH.toString(), true);
if(maxManaLH.equals(0))
if(maxMana.equals(0))
return Math.floor(Date.now() / 1000);
return Number.parseInt(this.extract(this.proto.cpp_calculate_manabar_full_regeneration_time(now, maxManaLH.low, maxManaLH.high, currentManaLH.low, currentManaLH.high, lastUpdateTime)));
const manabarRegenerationTime = safeWasmCall(() => this.proto.cpp_calculate_manabar_full_regeneration_time(now, maxMana.low, maxMana.high, currentMana.low, currentMana.high, lastUpdateTime));
return Number.parseInt(this.extract(manabarRegenerationTime));
}
public suggestBrainKey(): IBrainKeyData {
const data = this.proto.cpp_suggest_brain_key();
const data = safeWasmCall(() => this.proto.cpp_suggest_brain_key());
return {
associatedPublicKey: data.associated_public_key as string,
......@@ -316,7 +317,7 @@ export class WaxBaseApi implements IWaxBaseInterface {
}
public getPrivateKeyFromPassword(account: string, role: string, password: string): IPrivateKeyData {
const data = this.proto.cpp_generate_private_key_password_based(account, role, password);
const data = safeWasmCall(() => this.proto.cpp_generate_private_key_password_based(account, role, password));
return {
associatedPublicKey: data.associated_public_key as string,
......@@ -329,25 +330,27 @@ export class WaxBaseApi implements IWaxBaseInterface {
const totalVestingFundHiveAsset = this.createAssetWithRequiredSymbol(EAssetName.HIVE, totalVestingFundHive);
const totalVestingSharesAsset = this.createAssetWithRequiredSymbol(EAssetName.VESTS, totalVestingShares);
return this.proto.cpp_calculate_account_hp(vestsAsset, totalVestingFundHiveAsset, totalVestingSharesAsset) as NaiAsset;
return safeWasmCall(() => this.proto.cpp_calculate_account_hp(vestsAsset, totalVestingFundHiveAsset, totalVestingSharesAsset) as NaiAsset);
}
public calculateWitnessVotesHp(votes: number, totalVestingFundHive: TNaiAssetSource, totalVestingShares: TNaiAssetSource): NaiAsset {
const totalVestingFundHiveAsset = this.createAssetWithRequiredSymbol(EAssetName.HIVE, totalVestingFundHive);
const totalVestingSharesAsset = this.createAssetWithRequiredSymbol(EAssetName.VESTS, totalVestingShares);
return this.proto.cpp_calculate_witness_votes_hp(votes, votes, totalVestingFundHiveAsset, totalVestingSharesAsset) as NaiAsset;
return safeWasmCall(() => this.proto.cpp_calculate_witness_votes_hp(votes, votes, totalVestingFundHiveAsset, totalVestingSharesAsset) as NaiAsset);
}
public calculateHpApr(headBlockNum: number, vestingRewardPercent: number, virtualSupply: TNaiAssetSource, totalVestingFundHive: TNaiAssetSource): number {
const virtualSupplyAsset = this.createAssetWithRequiredSymbol(EAssetName.HIVE, virtualSupply);
const totalVestingFundHiveAsset = this.createAssetWithRequiredSymbol(EAssetName.HIVE, totalVestingFundHive);
return Number.parseFloat(this.extract(this.proto.cpp_calculate_hp_apr(headBlockNum, vestingRewardPercent, virtualSupplyAsset, totalVestingFundHiveAsset)));
const hpApr = safeWasmCall(() => this.proto.cpp_calculate_hp_apr(headBlockNum, vestingRewardPercent, virtualSupplyAsset, totalVestingFundHiveAsset));
return Number.parseFloat(this.extract(hpApr));
}
public delete(): void {
this.proto.delete();
safeWasmCall(() => this.proto.delete());
}
}
import type { IHiveChainInterface, IWaxOptionsChain } from "../interfaces.js";
// @ts-expect-error ts(6133) Type WaxError is used in JSDoc
import type { WaxError } from "../errors";
import { HiveChainApi } from "./chain_api.js";
import { safeAsyncWasmCall } from "./util/wasm_errors.js";
import MainModuleFunction from "../wax_module.js";
import { DEFAULT_WAX_OPTIONS } from "./base.js";
......@@ -23,7 +21,7 @@ export const DEFAULT_WAX_OPTIONS_CHAIN: IWaxOptionsChain = {
* @throws {WaxError} on any Wax API-related error
*/
export const createHiveChain = async(options: Partial<IWaxOptionsChain> = {}): Promise<IHiveChainInterface> => {
const waxProvider = await MainModuleFunction();
const waxProvider = await safeAsyncWasmCall(() => MainModuleFunction());
const apiOptions: IWaxOptionsChain = { ...DEFAULT_WAX_OPTIONS_CHAIN, ...options };
......
......@@ -7,6 +7,7 @@ import { plainToInstance } from "class-transformer";
import { validateOrReject } from "class-validator";
import { WaxError, WaxChainApiError } from "../errors.js";
import { safeWasmCall } from './util/wasm_errors.js';
import { ONE_HUNDRED_PERCENT, WaxBaseApi } from "./base_api.js";
import { HiveApiTypes, HiveRestApiTypes } from "./chain_api_data.js";
import { IDetailedResponseData, IRequestOptions, RequestHelper } from "./healthchecker/request_helper.js";
......@@ -436,11 +437,11 @@ export class HiveChainApi extends WaxBaseApi implements IHiveChainInterface {
const encrypted = wallet.encryptData(content, from, to);
return this.proto.cpp_crypto_memo_dump_string({
return safeWasmCall(() => this.proto.cpp_crypto_memo_dump_string({
content: encrypted,
from,
to
});
}));
}
private async getManabarDataArguments(accountName: string, manabarType: EManabarType): Promise<Parameters<WaxBaseApi['calculateCurrentManabarValue']>> {
......
......@@ -8,6 +8,7 @@ import { OperationBase } from "./operation_base";
import { EEncryptionType, EncryptionVisitor } from "./encryption_visitor.js";
import { WaxError } from "../errors.js";
import type { ApiTransaction } from "./api";
import { safeWasmCall } from "./util/wasm_errors";
type TIndexBeginEncryption = {
mainEncryptionKey: TPublicKey;
......@@ -35,7 +36,7 @@ export class Transaction implements ITransaction, IEncryptingTransaction {
private expirationTime?: TTimestamp;
private taposRefer(hex: TBlockHash): { ref_block_num: number; ref_block_prefix: number } {
return this.api.proto.cpp_get_tapos_data(hex);
return safeWasmCall(() => this.api.proto.cpp_get_tapos_data(hex));
}
private indexKeeper: Array<TIndexKeeperNode> = [];
......@@ -81,10 +82,11 @@ export class Transaction implements ITransaction, IEncryptingTransaction {
}
public static fromApi(api: WaxBaseApi, transactionObject: string | object): Transaction {
if(typeof transactionObject === 'object')
transactionObject = JSON.stringify(transactionObject);
const transactionStringified = typeof transactionObject === 'string' ? transactionObject : JSON.stringify(transactionObject);
const serialized = api.extract(api.proto.cpp_api_to_proto(transactionObject));
const protoData = safeWasmCall(() => api.proto.cpp_api_to_proto(transactionStringified));
const serialized = api.extract(protoData);
const tx = transaction.fromJSON(JSON.parse(serialized));
......@@ -92,7 +94,9 @@ export class Transaction implements ITransaction, IEncryptingTransaction {
}
public toApi(): string {
const serialized = this.api.extract(this.api.proto.cpp_proto_to_api(this.toString()));
const apiData = safeWasmCall(() => this.api.proto.cpp_proto_to_api(this.toString()));
const serialized = this.api.extract(apiData);
return serialized;
}
......@@ -102,7 +106,9 @@ export class Transaction implements ITransaction, IEncryptingTransaction {
}
public toLegacyApi(): string {
const serialized = this.api.extract(this.api.proto.cpp_proto_to_legacy_api(this.toString()));
const apiData = safeWasmCall(() => this.api.proto.cpp_proto_to_legacy_api(this.toString()));
const serialized = this.api.extract(apiData);
return serialized;
}
......@@ -158,33 +164,33 @@ export class Transaction implements ITransaction, IEncryptingTransaction {
public get sigDigest(): string {
const tx = this.toString();
const sigDigest: string = this.api.extract(this.api.proto.cpp_calculate_sig_digest(tx, this.api.chainId));
const sigDigest = safeWasmCall(() => this.api.proto.cpp_calculate_sig_digest(tx, this.api.chainId));
return sigDigest;
return this.api.extract(sigDigest);
}
public get legacy_sigDigest(): string {
const tx = this.toString();
const sigDigest: string = this.api.extract(this.api.proto.cpp_calculate_legacy_sig_digest(tx, this.api.chainId));
const legacySigDigest = safeWasmCall(() => this.api.proto.cpp_calculate_legacy_sig_digest(tx, this.api.chainId));
return sigDigest;
return this.api.extract(legacySigDigest);
}
public get id(): TTransactionId {
const tx = this.toString();
const transactionId: string = this.api.extract(this.api.proto.cpp_calculate_transaction_id(tx));
const transactionId = safeWasmCall(() => this.api.proto.cpp_calculate_transaction_id(tx));
return transactionId;
return this.api.extract(transactionId);
}
public get legacy_id(): TTransactionId {
const tx = this.toString();
const transactionId: string = this.api.extract(this.api.proto.cpp_calculate_legacy_transaction_id(tx));
const legacyTransactionId = safeWasmCall(() => this.api.proto.cpp_calculate_legacy_transaction_id(tx));
return transactionId;
return this.api.extract(legacyTransactionId);
}
public get requiredAuthorities(): TTransactionRequiredAuthorities {
......@@ -195,7 +201,7 @@ export class Transaction implements ITransaction, IEncryptingTransaction {
const owner: Set<string> = new Set();
const other: Array<authority> = [];
const res = this.api.proto.cpp_collect_transaction_required_authorities(tx);
const res = safeWasmCall(() => this.api.proto.cpp_collect_transaction_required_authorities(tx));
for(let i = 0; i < res.posting_accounts.size(); i++)
posting.add(res.posting_accounts.get(i) as string);
......@@ -245,7 +251,9 @@ export class Transaction implements ITransaction, IEncryptingTransaction {
public validate(): void {
const tx = this.toString();
this.api.extract(this.api.proto.cpp_validate_transaction(tx));
const validationResult = safeWasmCall(() => this.api.proto.cpp_validate_transaction(tx));
this.api.extract(validationResult);
}
private applyExpiration(): void {
......
import { WaxError } from "../../errors.js";
export const safeWasmCall = <T extends () => any>(fn: T): ReturnType<T> => {
try {
return fn()
} catch (error) {
throw new WaxError(`Error during Wasm call: ${error instanceof Error ? error.message : error}`);
}
};
export const safeAsyncWasmCall = async <T extends () => any>(fn: T): Promise<ReturnType<T>> => {
try {
return await fn();
} catch (error) {
throw new WaxError(`Error during Wasm call: ${error instanceof Error ? error.message : error}`);
}
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment