sui
sui copied to clipboard
ts-sdk: check if object id /address/transaction digest is valid before querying fullnode
Motivation
We saw a lot of errors on the fullnode due to the caller providing invalid transaction digest/object ids:
Deserialization to "sui_types::base_types::TransactionDigest" failed. Error: Error("byte deserialization failed, cause by: invalid Base64 encoding\n\nStack backtrace:\n
method_call{method=sui_getObject}: sui_json_rpc::api: Error parsing "object_id" as "ObjectID": InvalidParams(invalid type: null, expected a string at line 1 column 4
2022-10-19 11:17:58
2022-10-19T18:17:58.924575Z ERROR method_call{method=sui_getObject}: jsonrpsee_types::params: [next_inner] Deserialization to "sui_types::base_types::ObjectID" failed. Error: Error("byte deserialization failed, cause by: AccountAddressParseError", line: 0, column: 0), input JSON: "\"\"]"Show context
Task description
For all functions in this file, - If the function input involves TransactionDigest, we should call this function to validate the input before making a request to the rpc server
- if the function input involves
SuiAddressorObjectId, we should callisValidSuiAddress(normalizeSuiAddress())to validate the input before making a request to the rpc server
Caveats
We sometimes used plain string to represent the SuiAddress/ObjectId/TransationDigest, we should update these as well
Example:
https://github.com/MystenLabs/sui/blob/main/sdk/typescript/src/providers/json-rpc-provider.ts#L393-L407
async getObjectBatch(objectIds: string[]): Promise<GetObjectDataResponse[]> {
const requests = objectIds.map((id) => ({
method: 'sui_getObject',
args: [id],
}));
try {
return await this.client.batchRequestWithType(
requests,
isGetObjectDataResponse,
this.options.skipDataValidation
);
} catch (err) {
throw new Error(`Error fetching object info: ${err} for id ${objectIds}`);
}
}
Should become
// note that we replace `string[]` with `ObjectId[]` here
async getObjectBatch(objectIds: ObjectId[]): Promise<GetObjectDataResponse[]> {
// call validate function
validateObjectIds(objectIds);
const requests = objectIds.map((id) => ({
method: 'sui_getObject',
args: [id],
}));
try {
return await this.client.batchRequestWithType(
requests,
isGetObjectDataResponse,
this.options.skipDataValidation
);
} catch (err) {
throw new Error(`Error fetching object info: ${err} for id ${objectIds}`);
}
}
function validateObjectIds(objectIds: string | string[]): void {
const ids = typeof objectIds == 'string' ? [objectIds]: objectIds;
objectIds.forEach(id => {
if (!isValidSuiObjectId(normalizeSuiObjectId(id))) {
throw new Error(`Invalid Sui object id ${id}`)
}
);
}