question
why to we sometimes call nearlib
methods with a hash as string and other times use a hash as UInt8Array?
detail
JsonRpcProvider
has several methods for fetching network info including fetching a block by "id" which can be an integer or hash (as string), a chunk by hash (as string) and transaction by hash (as UInt8Array).
class JsonRpcProvider extends Provider {
async block(blockId: BlockId): Promise<BlockResult> {}
async chunk(chunkId: ChunkId): Promise<ChunkResult> {}
async txStatus(txHash: Uint8Array, accountId: string): Promise<FinalExecutionOutcome> {}
}
sample code that exercises these methods require some inconsistent thinking in terms of the interface and this adds friction to learning
for example,
retrieving a block
// using the previous snippet to pull the latest block hash
let chain = (await near.connection.provider.status()).sync_info
let id = chain.latest_block_hash
// let id = chain.latest_block_height // <-- this also works here
// we can pass the results to the provider.block method
await near.connection.provider.block(id)
retrieving a chunk
// assume here we use the block data above to fetch chunks from the block
// and identify this chunk hash as interesting ...
let hash = "6SrBkhwVLAZC2YQJG3YUSef2UGf7UxwpsLZEY3dsZMKb"
await near.connection.provider.chunk(hash)
--> and here's the inconsistency <--
retrieving a transaction
// assume here we find a transaction in the chunk above that we want to inspect
// but we can't use the txHash directly, we have to decode it
let txHash = "3L37n7LowxfpFEJcQvYmoQPo4NpgV2ZUmr4vXSBYhxPL"
let decodedTxHash = nearlib.utils.serialize.base_decode("3L37n7LowxfpFEJcQvYmoQPo4NpgV2ZUmr4vXSBYhxPL")
await near.connection.provider.txStatus(decodedTxHash, '')
this may be my misunderstanding but why can't we just use the transaction hash here directly? seems like we're just encoding it again inside the implementation (and accountId
accepts an empty string so i'm not sure why that's even exposed in this interface)
async txStatus(txHash: Uint8Array, accountId: string): Promise<FinalExecutionOutcome> {
return this.sendJsonRpc('tx', [base_encode(txHash), accountId]).then(adaptTransactionResult);
}
a naive glance (i don't know Rust) at the nearcore
JSON RPC client decodes the transaction hash again (and seems to require the accountId
parameter)
async fn tx_status(&self, params: Option<Value>) -> Result<Value, RpcError> {
let (hash, account_id) = parse_params::<(String, String)>(params)?;
/// @amgando -- this line seems to decode the transaction again
let tx_hash = from_base_or_parse_err(hash).and_then(|bytes| {
CryptoHash::try_from(bytes).map_err(|err| RpcError::parse_error(err.to_string()))
})?;
let result = self
.client_addr
.send(NetworkClientMessages::TxStatus {
tx_hash,
signer_account_id: account_id.clone(), /// @amgando -- not sure why account_id isn't just an empty string here
})
.compat()
.map_err(|err| RpcError::server_error(Some(convert_mailbox_error(err))))
.await?;
self.tx_polling(result, tx_hash, account_id).await
}