This commit is contained in:
Luke Parker 2023-07-10 13:33:08 -04:00
parent 7fa5d291b8
commit 3480fc5e16
No known key found for this signature in database

View file

@ -40,8 +40,10 @@ pub enum RpcError {
ConnectionError, ConnectionError,
#[error("request had an error: {0:?}")] #[error("request had an error: {0:?}")]
RequestError(Error), RequestError(Error),
#[error("node sent an invalid response")] #[error("node replied with invalid JSON")]
InvalidResponse, InvalidJson(serde_json::error::Category),
#[error("node sent an invalid response ({0})")]
InvalidResponse(&'static str),
#[error("node was missing expected methods")] #[error("node was missing expected methods")]
MissingMethods(HashSet<&'static str>), MissingMethods(HashSet<&'static str>),
} }
@ -117,7 +119,7 @@ impl Rpc {
.map_err(|_| RpcError::ConnectionError)?; .map_err(|_| RpcError::ConnectionError)?;
let res: RpcResponse<Response> = let res: RpcResponse<Response> =
serde_json::from_str(&res).map_err(|_| RpcError::InvalidResponse)?; serde_json::from_str(&res).map_err(|e| RpcError::InvalidJson(e.classify()))?;
match res { match res {
RpcResponse::Ok { result } => Ok(result), RpcResponse::Ok { result } => Ok(result),
RpcResponse::Err { error } => Err(RpcError::RequestError(error)), RpcResponse::Err { error } => Err(RpcError::RequestError(error)),
@ -160,13 +162,15 @@ impl Rpc {
/// Get a block by its hash. /// Get a block by its hash.
pub async fn get_block(&self, hash: &[u8; 32]) -> Result<Block, RpcError> { pub async fn get_block(&self, hash: &[u8; 32]) -> Result<Block, RpcError> {
let hex = self.rpc_call::<String>("getblock", json!([hex::encode(hash), 0])).await?; let hex = self.rpc_call::<String>("getblock", json!([hex::encode(hash), 0])).await?;
let bytes: Vec<u8> = FromHex::from_hex(&hex).map_err(|_| RpcError::InvalidResponse)?; let bytes: Vec<u8> = FromHex::from_hex(&hex)
let block: Block = encode::deserialize(&bytes).map_err(|_| RpcError::InvalidResponse)?; .map_err(|_| RpcError::InvalidResponse("node didn't use hex to encode the block"))?;
let block: Block = encode::deserialize(&bytes)
.map_err(|_| RpcError::InvalidResponse("node sent an improperly serialized block"))?;
let mut block_hash = *block.block_hash().as_raw_hash().as_byte_array(); let mut block_hash = *block.block_hash().as_raw_hash().as_byte_array();
block_hash.reverse(); block_hash.reverse();
if hash != &block_hash { if hash != &block_hash {
Err(RpcError::InvalidResponse)?; Err(RpcError::InvalidResponse("node replied with a different block"))?;
} }
Ok(block) Ok(block)
@ -176,7 +180,7 @@ impl Rpc {
pub async fn send_raw_transaction(&self, tx: &Transaction) -> Result<Txid, RpcError> { pub async fn send_raw_transaction(&self, tx: &Transaction) -> Result<Txid, RpcError> {
let txid = self.rpc_call("sendrawtransaction", json!([encode::serialize_hex(tx)])).await?; let txid = self.rpc_call("sendrawtransaction", json!([encode::serialize_hex(tx)])).await?;
if txid != tx.txid() { if txid != tx.txid() {
Err(RpcError::InvalidResponse)?; Err(RpcError::InvalidResponse("returned TX ID inequals calculated TX ID"))?;
} }
Ok(txid) Ok(txid)
} }
@ -184,13 +188,15 @@ impl Rpc {
/// Get a transaction by its hash. /// Get a transaction by its hash.
pub async fn get_transaction(&self, hash: &[u8; 32]) -> Result<Transaction, RpcError> { pub async fn get_transaction(&self, hash: &[u8; 32]) -> Result<Transaction, RpcError> {
let hex = self.rpc_call::<String>("getrawtransaction", json!([hex::encode(hash)])).await?; let hex = self.rpc_call::<String>("getrawtransaction", json!([hex::encode(hash)])).await?;
let bytes: Vec<u8> = FromHex::from_hex(&hex).map_err(|_| RpcError::InvalidResponse)?; let bytes: Vec<u8> = FromHex::from_hex(&hex)
let tx: Transaction = encode::deserialize(&bytes).map_err(|_| RpcError::InvalidResponse)?; .map_err(|_| RpcError::InvalidResponse("node didn't use hex to encode the transaction"))?;
let tx: Transaction = encode::deserialize(&bytes)
.map_err(|_| RpcError::InvalidResponse("node sent an improperly serialized transaction"))?;
let mut tx_hash = *tx.txid().as_raw_hash().as_byte_array(); let mut tx_hash = *tx.txid().as_raw_hash().as_byte_array();
tx_hash.reverse(); tx_hash.reverse();
if hash != &tx_hash { if hash != &tx_hash {
Err(RpcError::InvalidResponse)?; Err(RpcError::InvalidResponse("node replied with a different transaction"))?;
} }
Ok(tx) Ok(tx)