feat: web3.js RPC errors now hold the error `code` and `data` on the error object (#26318)

feat: web3.js RPC errors now hold the error code on the error object
This commit is contained in:
Steven Luscher 2022-06-30 13:08:10 -07:00 committed by GitHub
parent 54cd31e9e2
commit e17ed6b2b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 143 additions and 99 deletions

View File

@ -7,6 +7,7 @@ use {
thiserror::Error, thiserror::Error,
}; };
// Keep in sync with web3.js/src/errors.ts
pub const JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP: i64 = -32001; pub const JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP: i64 = -32001;
pub const JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE: i64 = -32002; pub const JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE: i64 = -32002;
pub const JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: i64 = -32003; pub const JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: i64 = -32003;

View File

@ -26,7 +26,7 @@ import RpcClient from 'jayson/lib/client/browser';
import {AgentManager} from './agent-manager'; import {AgentManager} from './agent-manager';
import {EpochSchedule} from './epoch-schedule'; import {EpochSchedule} from './epoch-schedule';
import {SendTransactionError} from './errors'; import {SendTransactionError, SolanaJSONRPCError} from './errors';
import fetchImpl, {Response} from './fetch-impl'; import fetchImpl, {Response} from './fetch-impl';
import {NonceAccount} from './nonce-account'; import {NonceAccount} from './nonce-account';
import {PublicKey} from './publickey'; import {PublicKey} from './publickey';
@ -2532,11 +2532,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getBalance', args); const unsafeRes = await this._rpcRequest('getBalance', args);
const res = create(unsafeRes, jsonRpcResultAndContext(number())); const res = create(unsafeRes, jsonRpcResultAndContext(number()));
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get balance for ' + res.error,
publicKey.toBase58() + `failed to get balance for ${publicKey.toBase58()}`,
': ' +
res.error.message,
); );
} }
return res.result; return res.result;
@ -2565,8 +2563,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getBlockTime', [slot]); const unsafeRes = await this._rpcRequest('getBlockTime', [slot]);
const res = create(unsafeRes, jsonRpcResult(nullable(number()))); const res = create(unsafeRes, jsonRpcResult(nullable(number())));
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get block time for slot ' + slot + ': ' + res.error.message, res.error,
`failed to get block time for slot ${slot}`,
); );
} }
return res.result; return res.result;
@ -2580,8 +2579,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('minimumLedgerSlot', []); const unsafeRes = await this._rpcRequest('minimumLedgerSlot', []);
const res = create(unsafeRes, jsonRpcResult(number())); const res = create(unsafeRes, jsonRpcResult(number()));
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get minimum ledger slot: ' + res.error.message, res.error,
'failed to get minimum ledger slot',
); );
} }
return res.result; return res.result;
@ -2594,8 +2594,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getFirstAvailableBlock', []); const unsafeRes = await this._rpcRequest('getFirstAvailableBlock', []);
const res = create(unsafeRes, SlotRpcResult); const res = create(unsafeRes, SlotRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get first available block: ' + res.error.message, res.error,
'failed to get first available block',
); );
} }
return res.result; return res.result;
@ -2624,7 +2625,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getSupply', [configArg]); const unsafeRes = await this._rpcRequest('getSupply', [configArg]);
const res = create(unsafeRes, GetSupplyRpcResult); const res = create(unsafeRes, GetSupplyRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get supply: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get supply');
} }
return res.result; return res.result;
} }
@ -2640,7 +2641,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getTokenSupply', args); const unsafeRes = await this._rpcRequest('getTokenSupply', args);
const res = create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult)); const res = create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult));
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get token supply: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get token supply');
} }
return res.result; return res.result;
} }
@ -2656,8 +2657,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getTokenAccountBalance', args); const unsafeRes = await this._rpcRequest('getTokenAccountBalance', args);
const res = create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult)); const res = create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult));
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get token account balance: ' + res.error.message, res.error,
'failed to get token account balance',
); );
} }
return res.result; return res.result;
@ -2690,11 +2692,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args); const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args);
const res = create(unsafeRes, GetTokenAccountsByOwner); const res = create(unsafeRes, GetTokenAccountsByOwner);
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get token accounts owned by account ' + res.error,
ownerAddress.toBase58() + `failed to get token accounts owned by account ${ownerAddress.toBase58()}`,
': ' +
res.error.message,
); );
} }
return res.result; return res.result;
@ -2725,11 +2725,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args); const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args);
const res = create(unsafeRes, GetParsedTokenAccountsByOwner); const res = create(unsafeRes, GetParsedTokenAccountsByOwner);
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get token accounts owned by account ' + res.error,
ownerAddress.toBase58() + `failed to get token accounts owned by account ${ownerAddress.toBase58()}`,
': ' +
res.error.message,
); );
} }
return res.result; return res.result;
@ -2749,7 +2747,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getLargestAccounts', args); const unsafeRes = await this._rpcRequest('getLargestAccounts', args);
const res = create(unsafeRes, GetLargestAccountsRpcResult); const res = create(unsafeRes, GetLargestAccountsRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get largest accounts: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get largest accounts');
} }
return res.result; return res.result;
} }
@ -2766,8 +2764,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getTokenLargestAccounts', args); const unsafeRes = await this._rpcRequest('getTokenLargestAccounts', args);
const res = create(unsafeRes, GetTokenLargestAccountsResult); const res = create(unsafeRes, GetTokenLargestAccountsResult);
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get token largest accounts: ' + res.error.message, res.error,
'failed to get token largest accounts',
); );
} }
return res.result; return res.result;
@ -2794,11 +2793,9 @@ export class Connection {
jsonRpcResultAndContext(nullable(AccountInfoResult)), jsonRpcResultAndContext(nullable(AccountInfoResult)),
); );
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get info about account ' + res.error,
publicKey.toBase58() + `failed to get info about account ${publicKey.toBase58()}`,
': ' +
res.error.message,
); );
} }
return res.result; return res.result;
@ -2824,11 +2821,9 @@ export class Connection {
jsonRpcResultAndContext(nullable(ParsedAccountInfoResult)), jsonRpcResultAndContext(nullable(ParsedAccountInfoResult)),
); );
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get info about account ' + res.error,
publicKey.toBase58() + `failed to get info about account ${publicKey.toBase58()}`,
': ' +
res.error.message,
); );
} }
return res.result; return res.result;
@ -2871,8 +2866,9 @@ export class Connection {
jsonRpcResultAndContext(array(nullable(AccountInfoResult))), jsonRpcResultAndContext(array(nullable(AccountInfoResult))),
); );
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get info for accounts ' + keys + ': ' + res.error.message, res.error,
`failed to get info for accounts ${keys}`,
); );
} }
return res.result; return res.result;
@ -2915,10 +2911,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getStakeActivation', args); const unsafeRes = await this._rpcRequest('getStakeActivation', args);
const res = create(unsafeRes, jsonRpcResult(StakeActivationResult)); const res = create(unsafeRes, jsonRpcResult(StakeActivationResult));
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
`failed to get Stake Activation ${publicKey.toBase58()}: ${ res.error,
res.error.message `failed to get Stake Activation ${publicKey.toBase58()}`,
}`,
); );
} }
return res.result; return res.result;
@ -2945,11 +2940,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getProgramAccounts', args); const unsafeRes = await this._rpcRequest('getProgramAccounts', args);
const res = create(unsafeRes, jsonRpcResult(array(KeyedAccountInfoResult))); const res = create(unsafeRes, jsonRpcResult(array(KeyedAccountInfoResult)));
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get accounts owned by program ' + res.error,
programId.toBase58() + `failed to get accounts owned by program ${programId.toBase58()}`,
': ' +
res.error.message,
); );
} }
return res.result; return res.result;
@ -2983,11 +2976,9 @@ export class Connection {
jsonRpcResult(array(KeyedParsedAccountInfoResult)), jsonRpcResult(array(KeyedParsedAccountInfoResult)),
); );
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get accounts owned by program ' + res.error,
programId.toBase58() + `failed to get accounts owned by program ${programId.toBase58()}`,
': ' +
res.error.message,
); );
} }
return res.result; return res.result;
@ -3142,7 +3133,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getClusterNodes', []); const unsafeRes = await this._rpcRequest('getClusterNodes', []);
const res = create(unsafeRes, jsonRpcResult(array(ContactInfoResult))); const res = create(unsafeRes, jsonRpcResult(array(ContactInfoResult)));
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get cluster nodes: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get cluster nodes');
} }
return res.result; return res.result;
} }
@ -3155,7 +3146,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getVoteAccounts', args); const unsafeRes = await this._rpcRequest('getVoteAccounts', args);
const res = create(unsafeRes, GetVoteAccounts); const res = create(unsafeRes, GetVoteAccounts);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get vote accounts: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get vote accounts');
} }
return res.result; return res.result;
} }
@ -3177,7 +3168,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getSlot', args); const unsafeRes = await this._rpcRequest('getSlot', args);
const res = create(unsafeRes, jsonRpcResult(number())); const res = create(unsafeRes, jsonRpcResult(number()));
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get slot: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get slot');
} }
return res.result; return res.result;
} }
@ -3199,7 +3190,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getSlotLeader', args); const unsafeRes = await this._rpcRequest('getSlotLeader', args);
const res = create(unsafeRes, jsonRpcResult(string())); const res = create(unsafeRes, jsonRpcResult(string()));
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get slot leader: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get slot leader');
} }
return res.result; return res.result;
} }
@ -3218,7 +3209,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getSlotLeaders', args); const unsafeRes = await this._rpcRequest('getSlotLeaders', args);
const res = create(unsafeRes, jsonRpcResult(array(PublicKeyFromString))); const res = create(unsafeRes, jsonRpcResult(array(PublicKeyFromString)));
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get slot leaders: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get slot leaders');
} }
return res.result; return res.result;
} }
@ -3253,7 +3244,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getSignatureStatuses', params); const unsafeRes = await this._rpcRequest('getSignatureStatuses', params);
const res = create(unsafeRes, GetSignatureStatusesRpcResult); const res = create(unsafeRes, GetSignatureStatusesRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get signature status: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get signature status');
} }
return res.result; return res.result;
} }
@ -3275,7 +3266,10 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getTransactionCount', args); const unsafeRes = await this._rpcRequest('getTransactionCount', args);
const res = create(unsafeRes, jsonRpcResult(number())); const res = create(unsafeRes, jsonRpcResult(number()));
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get transaction count: ' + res.error.message); throw new SolanaJSONRPCError(
res.error,
'failed to get transaction count',
);
} }
return res.result; return res.result;
} }
@ -3303,7 +3297,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getInflationGovernor', args); const unsafeRes = await this._rpcRequest('getInflationGovernor', args);
const res = create(unsafeRes, GetInflationGovernorRpcResult); const res = create(unsafeRes, GetInflationGovernorRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get inflation: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get inflation');
} }
return res.result; return res.result;
} }
@ -3330,7 +3324,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getInflationReward', args); const unsafeRes = await this._rpcRequest('getInflationReward', args);
const res = create(unsafeRes, GetInflationRewardResult); const res = create(unsafeRes, GetInflationRewardResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get inflation reward: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get inflation reward');
} }
return res.result; return res.result;
} }
@ -3352,7 +3346,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getEpochInfo', args); const unsafeRes = await this._rpcRequest('getEpochInfo', args);
const res = create(unsafeRes, GetEpochInfoRpcResult); const res = create(unsafeRes, GetEpochInfoRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get epoch info: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get epoch info');
} }
return res.result; return res.result;
} }
@ -3364,7 +3358,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getEpochSchedule', []); const unsafeRes = await this._rpcRequest('getEpochSchedule', []);
const res = create(unsafeRes, GetEpochScheduleRpcResult); const res = create(unsafeRes, GetEpochScheduleRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get epoch schedule: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get epoch schedule');
} }
const epochSchedule = res.result; const epochSchedule = res.result;
return new EpochSchedule( return new EpochSchedule(
@ -3384,7 +3378,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getLeaderSchedule', []); const unsafeRes = await this._rpcRequest('getLeaderSchedule', []);
const res = create(unsafeRes, GetLeaderScheduleRpcResult); const res = create(unsafeRes, GetLeaderScheduleRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get leader schedule: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get leader schedule');
} }
return res.result; return res.result;
} }
@ -3425,7 +3419,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getRecentBlockhash', args); const unsafeRes = await this._rpcRequest('getRecentBlockhash', args);
const res = create(unsafeRes, GetRecentBlockhashAndContextRpcResult); const res = create(unsafeRes, GetRecentBlockhashAndContextRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get recent blockhash: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get recent blockhash');
} }
return res.result; return res.result;
} }
@ -3444,8 +3438,9 @@ export class Connection {
); );
const res = create(unsafeRes, GetRecentPerformanceSamplesRpcResult); const res = create(unsafeRes, GetRecentPerformanceSamplesRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get recent performance samples: ' + res.error.message, res.error,
'failed to get recent performance samples',
); );
} }
@ -3469,7 +3464,7 @@ export class Connection {
const res = create(unsafeRes, GetFeeCalculatorRpcResult); const res = create(unsafeRes, GetFeeCalculatorRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get fee calculator: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get fee calculator');
} }
const {context, value} = res.result; const {context, value} = res.result;
return { return {
@ -3491,7 +3486,7 @@ export class Connection {
const res = create(unsafeRes, jsonRpcResultAndContext(nullable(number()))); const res = create(unsafeRes, jsonRpcResultAndContext(nullable(number())));
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get slot: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get slot');
} }
if (res.result === null) { if (res.result === null) {
throw new Error('invalid blockhash'); throw new Error('invalid blockhash');
@ -3549,7 +3544,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getLatestBlockhash', args); const unsafeRes = await this._rpcRequest('getLatestBlockhash', args);
const res = create(unsafeRes, GetLatestBlockhashRpcResult); const res = create(unsafeRes, GetLatestBlockhashRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get latest blockhash: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get latest blockhash');
} }
return res.result; return res.result;
} }
@ -3561,7 +3556,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getVersion', []); const unsafeRes = await this._rpcRequest('getVersion', []);
const res = create(unsafeRes, jsonRpcResult(VersionResult)); const res = create(unsafeRes, jsonRpcResult(VersionResult));
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get version: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get version');
} }
return res.result; return res.result;
} }
@ -3573,7 +3568,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getGenesisHash', []); const unsafeRes = await this._rpcRequest('getGenesisHash', []);
const res = create(unsafeRes, jsonRpcResult(string())); const res = create(unsafeRes, jsonRpcResult(string()));
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get genesis hash: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get genesis hash');
} }
return res.result; return res.result;
} }
@ -3593,7 +3588,7 @@ export class Connection {
const res = create(unsafeRes, GetBlockRpcResult); const res = create(unsafeRes, GetBlockRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get confirmed block: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block');
} }
const result = res.result; const result = res.result;
@ -3631,8 +3626,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getBlockHeight', args); const unsafeRes = await this._rpcRequest('getBlockHeight', args);
const res = create(unsafeRes, jsonRpcResult(number())); const res = create(unsafeRes, jsonRpcResult(number()));
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get block height information: ' + res.error.message, res.error,
'failed to get block height information',
); );
} }
@ -3660,8 +3656,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getBlockProduction', args); const unsafeRes = await this._rpcRequest('getBlockProduction', args);
const res = create(unsafeRes, BlockProductionResponseStruct); const res = create(unsafeRes, BlockProductionResponseStruct);
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get block production information: ' + res.error.message, res.error,
'failed to get block production information',
); );
} }
@ -3682,7 +3679,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getTransaction', args); const unsafeRes = await this._rpcRequest('getTransaction', args);
const res = create(unsafeRes, GetTransactionRpcResult); const res = create(unsafeRes, GetTransactionRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get transaction: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
} }
const result = res.result; const result = res.result;
@ -3712,7 +3709,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getTransaction', args); const unsafeRes = await this._rpcRequest('getTransaction', args);
const res = create(unsafeRes, GetParsedTransactionRpcResult); const res = create(unsafeRes, GetParsedTransactionRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get transaction: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
} }
return res.result; return res.result;
} }
@ -3740,7 +3737,7 @@ export class Connection {
const res = unsafeRes.map((unsafeRes: any) => { const res = unsafeRes.map((unsafeRes: any) => {
const res = create(unsafeRes, GetParsedTransactionRpcResult); const res = create(unsafeRes, GetParsedTransactionRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get transactions: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get transactions');
} }
return res.result; return res.result;
}); });
@ -3768,7 +3765,7 @@ export class Connection {
const res = unsafeRes.map((unsafeRes: any) => { const res = unsafeRes.map((unsafeRes: any) => {
const res = create(unsafeRes, GetTransactionRpcResult); const res = create(unsafeRes, GetTransactionRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get transactions: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get transactions');
} }
const result = res.result; const result = res.result;
if (!result) return result; if (!result) return result;
@ -3800,7 +3797,7 @@ export class Connection {
const res = create(unsafeRes, GetConfirmedBlockRpcResult); const res = create(unsafeRes, GetConfirmedBlockRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get confirmed block: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block');
} }
const result = res.result; const result = res.result;
@ -3851,7 +3848,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getBlocks', args); const unsafeRes = await this._rpcRequest('getBlocks', args);
const res = create(unsafeRes, jsonRpcResult(array(number()))); const res = create(unsafeRes, jsonRpcResult(array(number())));
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get blocks: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get blocks');
} }
return res.result; return res.result;
} }
@ -3875,7 +3872,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getBlock', args); const unsafeRes = await this._rpcRequest('getBlock', args);
const res = create(unsafeRes, GetBlockSignaturesRpcResult); const res = create(unsafeRes, GetBlockSignaturesRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get block: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get block');
} }
const result = res.result; const result = res.result;
if (!result) { if (!result) {
@ -3905,7 +3902,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getConfirmedBlock', args); const unsafeRes = await this._rpcRequest('getConfirmedBlock', args);
const res = create(unsafeRes, GetBlockSignaturesRpcResult); const res = create(unsafeRes, GetBlockSignaturesRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get confirmed block: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block');
} }
const result = res.result; const result = res.result;
if (!result) { if (!result) {
@ -3927,7 +3924,7 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getConfirmedTransaction', args); const unsafeRes = await this._rpcRequest('getConfirmedTransaction', args);
const res = create(unsafeRes, GetTransactionRpcResult); const res = create(unsafeRes, GetTransactionRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error('failed to get transaction: ' + res.error.message); throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
} }
const result = res.result; const result = res.result;
@ -3958,8 +3955,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getConfirmedTransaction', args); const unsafeRes = await this._rpcRequest('getConfirmedTransaction', args);
const res = create(unsafeRes, GetParsedTransactionRpcResult); const res = create(unsafeRes, GetParsedTransactionRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get confirmed transaction: ' + res.error.message, res.error,
'failed to get confirmed transaction',
); );
} }
return res.result; return res.result;
@ -3990,8 +3988,9 @@ export class Connection {
const res = unsafeRes.map((unsafeRes: any) => { const res = unsafeRes.map((unsafeRes: any) => {
const res = create(unsafeRes, GetParsedTransactionRpcResult); const res = create(unsafeRes, GetParsedTransactionRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get confirmed transactions: ' + res.error.message, res.error,
'failed to get confirmed transactions',
); );
} }
return res.result; return res.result;
@ -4096,8 +4095,9 @@ export class Connection {
); );
const res = create(unsafeRes, GetConfirmedSignaturesForAddress2RpcResult); const res = create(unsafeRes, GetConfirmedSignaturesForAddress2RpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get confirmed signatures for address: ' + res.error.message, res.error,
'failed to get confirmed signatures for address',
); );
} }
return res.result; return res.result;
@ -4125,8 +4125,9 @@ export class Connection {
const unsafeRes = await this._rpcRequest('getSignaturesForAddress', args); const unsafeRes = await this._rpcRequest('getSignaturesForAddress', args);
const res = create(unsafeRes, GetSignaturesForAddressRpcResult); const res = create(unsafeRes, GetSignaturesForAddressRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'failed to get signatures for address: ' + res.error.message, res.error,
'failed to get signatures for address',
); );
} }
return res.result; return res.result;
@ -4198,8 +4199,9 @@ export class Connection {
]); ]);
const res = create(unsafeRes, RequestAirdropRpcResult); const res = create(unsafeRes, RequestAirdropRpcResult);
if ('error' in res) { if ('error' in res) {
throw new Error( throw new SolanaJSONRPCError(
'airdrop to ' + to.toBase58() + ' failed: ' + res.error.message, res.error,
`airdrop to ${to.toBase58()} failed`,
); );
} }
return res.result; return res.result;

View File

@ -7,3 +7,44 @@ export class SendTransactionError extends Error {
this.logs = logs; this.logs = logs;
} }
} }
// Keep in sync with client/src/rpc_custom_errors.rs
// Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/
export const SolanaJSONRPCErrorCode = {
JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP: -32001,
JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE: -32002,
JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: -32003,
JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE: -32004,
JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY: -32005,
JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: -32006,
JSON_RPC_SERVER_ERROR_SLOT_SKIPPED: -32007,
JSON_RPC_SERVER_ERROR_NO_SNAPSHOT: -32008,
JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED: -32009,
JSON_RPC_SERVER_ERROR_KEY_EXCLUDED_FROM_SECONDARY_INDEX: -32010,
JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE: -32011,
JSON_RPC_SCAN_ERROR: -32012,
JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_LEN_MISMATCH: -32013,
JSON_RPC_SERVER_ERROR_BLOCK_STATUS_NOT_AVAILABLE_YET: -32014,
JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION: -32015,
JSON_RPC_SERVER_ERROR_MIN_CONTEXT_SLOT_NOT_REACHED: -32016,
} as const;
export type SolanaJSONRPCErrorCodeEnum =
typeof SolanaJSONRPCErrorCode[keyof typeof SolanaJSONRPCErrorCode];
export class SolanaJSONRPCError extends Error {
code: SolanaJSONRPCErrorCodeEnum | unknown;
data?: any;
constructor(
{
code,
message,
data,
}: Readonly<{code: unknown; message: string; data?: any}>,
customMessage?: string,
) {
super(customMessage != null ? `${customMessage}: ${message}` : message);
this.code = code;
this.data = data;
this.name = 'SolanaJSONRPCError';
}
}