sui icon indicating copy to clipboard operation
sui copied to clipboard

ts-sdk: check if object id /address/transaction digest is valid before querying fullnode

Open 666lcz opened this issue 3 years ago • 0 comments

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 SuiAddress or ObjectId, we should call isValidSuiAddress(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}`)
     } 
  );
}

666lcz avatar Oct 19 '22 20:10 666lcz