Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

RPC: Improve error messages for decoding errors #28530

Merged
merged 1 commit into from
Oct 24, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 75 additions & 29 deletions rpc/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4429,7 +4429,7 @@ where
inc_new_counter_info!("rpc-base58_encoded_tx", 1);
if encoded.len() > MAX_BASE58_SIZE {
return Err(Error::invalid_params(format!(
"encoded {} too large: {} bytes (max: encoded/raw {}/{})",
"base58 encoded {} too large: {} bytes (max: encoded/raw {}/{})",
type_name::<T>(),
encoded.len(),
MAX_BASE58_SIZE,
Expand All @@ -4438,40 +4438,42 @@ where
}
bs58::decode(encoded)
.into_vec()
.map_err(|e| Error::invalid_params(format!("{:?}", e)))?
.map_err(|e| Error::invalid_params(format!("invalid base58 encoding: {:?}", e)))?
}
TransactionBinaryEncoding::Base64 => {
inc_new_counter_info!("rpc-base64_encoded_tx", 1);
if encoded.len() > MAX_BASE64_SIZE {
return Err(Error::invalid_params(format!(
"encoded {} too large: {} bytes (max: encoded/raw {}/{})",
"base64 encoded {} too large: {} bytes (max: encoded/raw {}/{})",
type_name::<T>(),
encoded.len(),
MAX_BASE64_SIZE,
PACKET_DATA_SIZE,
)));
}
base64::decode(encoded).map_err(|e| Error::invalid_params(format!("{:?}", e)))?
base64::decode(encoded)
.map_err(|e| Error::invalid_params(format!("invalid base64 encoding: {:?}", e)))?
}
};
if wire_output.len() > PACKET_DATA_SIZE {
let err = format!(
"encoded {} too large: {} bytes (max: {} bytes)",
return Err(Error::invalid_params(format!(
"decoded {} too large: {} bytes (max: {} bytes)",
type_name::<T>(),
wire_output.len(),
PACKET_DATA_SIZE
);
info!("{}", err);
return Err(Error::invalid_params(&err));
)));
}
bincode::options()
.with_limit(PACKET_DATA_SIZE as u64)
.with_fixint_encoding()
.allow_trailing_bytes()
.deserialize_from(&wire_output[..])
.map_err(|err| {
info!("deserialize error: {}", err);
Error::invalid_params(&err.to_string())
Error::invalid_params(format!(
"failed to deserialize {}: {}",
type_name::<T>(),
&err.to_string()
))
})
.map(|output| (wire_output, output))
}
Expand Down Expand Up @@ -8387,45 +8389,89 @@ pub mod tests {
// +2 because +1 still fits in base64 encoded worst-case
let too_big = PACKET_DATA_SIZE + 2;
let tx_ser = vec![0xffu8; too_big];

let tx58 = bs58::encode(&tx_ser).into_string();
let tx58_len = tx58.len();
let expect58 = Error::invalid_params(format!(
"encoded solana_sdk::transaction::Transaction too large: {} bytes (max: encoded/raw {}/{})",
tx58_len, MAX_BASE58_SIZE, PACKET_DATA_SIZE,
));
assert_eq!(
decode_and_deserialize::<Transaction>(tx58, TransactionBinaryEncoding::Base58)
.unwrap_err(),
expect58
);
Error::invalid_params(format!(
"base58 encoded solana_sdk::transaction::Transaction too large: {} bytes (max: encoded/raw {}/{})",
tx58_len, MAX_BASE58_SIZE, PACKET_DATA_SIZE,
)
));

let tx64 = base64::encode(&tx_ser);
let tx64_len = tx64.len();
let expect64 = Error::invalid_params(format!(
"encoded solana_sdk::transaction::Transaction too large: {} bytes (max: encoded/raw {}/{})",
tx64_len, MAX_BASE64_SIZE, PACKET_DATA_SIZE,
));
assert_eq!(
decode_and_deserialize::<Transaction>(tx64, TransactionBinaryEncoding::Base64)
.unwrap_err(),
expect64
);
Error::invalid_params(format!(
"base64 encoded solana_sdk::transaction::Transaction too large: {} bytes (max: encoded/raw {}/{})",
tx64_len, MAX_BASE64_SIZE, PACKET_DATA_SIZE,
)
));

let too_big = PACKET_DATA_SIZE + 1;
let tx_ser = vec![0x00u8; too_big];
let tx58 = bs58::encode(&tx_ser).into_string();
let expect = Error::invalid_params(format!(
"encoded solana_sdk::transaction::Transaction too large: {} bytes (max: {} bytes)",
too_big, PACKET_DATA_SIZE
));
assert_eq!(
decode_and_deserialize::<Transaction>(tx58, TransactionBinaryEncoding::Base58)
.unwrap_err(),
expect
Error::invalid_params(format!(
"decoded solana_sdk::transaction::Transaction too large: {} bytes (max: {} bytes)",
too_big, PACKET_DATA_SIZE
))
);

let tx64 = base64::encode(&tx_ser);
assert_eq!(
decode_and_deserialize::<Transaction>(tx64, TransactionBinaryEncoding::Base64)
.unwrap_err(),
expect
Error::invalid_params(format!(
"decoded solana_sdk::transaction::Transaction too large: {} bytes (max: {} bytes)",
too_big, PACKET_DATA_SIZE
))
);

let tx_ser = vec![0xffu8; PACKET_DATA_SIZE - 2];
let mut tx64 = base64::encode(&tx_ser);
assert_eq!(
decode_and_deserialize::<Transaction>(tx64.clone(), TransactionBinaryEncoding::Base64)
.unwrap_err(),
Error::invalid_params(
"failed to deserialize solana_sdk::transaction::Transaction: invalid value: \
continue signal on byte-three, expected a terminal signal on or before byte-three"
.to_string()
)
);

tx64.push('!');
assert_eq!(
decode_and_deserialize::<Transaction>(tx64, TransactionBinaryEncoding::Base64)
.unwrap_err(),
Error::invalid_params("invalid base64 encoding: InvalidByte(1640, 33)".to_string())
);

let mut tx58 = bs58::encode(&tx_ser).into_string();
assert_eq!(
decode_and_deserialize::<Transaction>(tx58.clone(), TransactionBinaryEncoding::Base58)
.unwrap_err(),
Error::invalid_params(
"failed to deserialize solana_sdk::transaction::Transaction: invalid value: \
continue signal on byte-three, expected a terminal signal on or before byte-three"
.to_string()
)
);

tx58.push('!');
assert_eq!(
decode_and_deserialize::<Transaction>(tx58, TransactionBinaryEncoding::Base58)
.unwrap_err(),
Error::invalid_params(
"invalid base58 encoding: InvalidCharacter { character: '!', index: 1680 }"
.to_string(),
)
);
}

Expand Down