use super::{
KnownMeta,
super::error::Error,
types::{authoring::v1::AuthoringMeta, authoring::v2::AuthoringMetaV2},
};
impl KnownMeta {
pub fn normalize(&self, data: &[u8]) -> Result<Vec<u8>, Error> {
Ok(match self {
KnownMeta::AuthoringMetaV1 => {
match AuthoringMeta::abi_decode(data) {
Ok(am) => am.abi_encode_validate()?,
_ => AuthoringMeta::abi_encode_validate(
&serde_json::from_str::<AuthoringMeta>(std::str::from_utf8(data)?)?,
)?,
}
}
KnownMeta::AuthoringMetaV2 => {
AuthoringMetaV2::abi_decode_validate(data)
.map_err(|e| Error::InvalidInput(e.to_string()))?;
data.to_vec()
}
_ => data.to_vec(),
})
}
}
#[cfg(all(test, not(target_family = "wasm")))]
mod tests {
use alloy::sol_types::SolValue;
use crate::error::Error;
use crate::meta::types::authoring::v1::{AuthoringMeta, AuthoringMetaItem};
use crate::meta::types::authoring::v2::AuthoringMetaV2Sol;
use crate::meta::KnownMeta;
fn authoring_meta_v2_abi(word: [u8; 32], description: &str) -> Vec<u8> {
vec![AuthoringMetaV2Sol {
word: word.into(),
description: description.to_string(),
}]
.abi_encode()
}
#[test]
fn test_normalize_op_v1_is_a_passthrough() {
let bytes = b"{ \"name\" : \"add\" }";
assert_eq!(KnownMeta::OpV1.normalize(bytes).unwrap(), bytes.to_vec());
}
#[test]
fn test_normalize_solidity_abi_v2_is_a_passthrough() {
let inputs: [&[u8]; 3] = [b"[ ]", b"not json at all", &[0xff, 0xfe]];
for bytes in inputs {
assert_eq!(
KnownMeta::SolidityAbiV2.normalize(bytes).unwrap(),
bytes.to_vec()
);
}
}
#[test]
fn test_normalize_interpreter_caller_meta_v1_is_a_passthrough() {
let bytes = br#"{"name":"Test Caller","abiName":"TestCaller","methods":[]}"#;
assert_eq!(
KnownMeta::InterpreterCallerMetaV1.normalize(bytes).unwrap(),
bytes.to_vec()
);
}
#[test]
fn test_normalize_passthrough_for_binary_metas() {
let data = vec![0x00, 0x01, 0xff];
assert_eq!(
KnownMeta::ExpressionDeployerV2BytecodeV1
.normalize(&data)
.unwrap(),
data
);
}
fn sample_authoring_meta() -> AuthoringMeta {
serde_json::from_str(
r#"[{"word":"stack","description":"Copies an existing value from the stack.","operandParserOffset":16}]"#,
)
.unwrap()
}
#[test]
fn test_normalize_authoring_meta_v1_abi_path() {
let authoring_meta = sample_authoring_meta();
let abi = authoring_meta.abi_encode_validate().unwrap();
let normalized = KnownMeta::AuthoringMetaV1.normalize(&abi).unwrap();
assert_eq!(normalized, abi);
}
#[test]
fn test_normalize_authoring_meta_v1_abi_invalid_rejected() {
let invalid = AuthoringMeta(vec![AuthoringMetaItem {
word: "NOTKEBAB".to_string(),
operand_parser_offset: 0,
description: "some description".to_string(),
}]);
let abi = invalid.abi_encode().unwrap();
let result = KnownMeta::AuthoringMetaV1.normalize(&abi);
assert!(matches!(result, Err(Error::ValidationErrors(_))));
}
#[test]
fn test_normalize_authoring_meta_v1_json_fallback() {
let json = r#"[{"word":"stack","description":"Copies an existing value from the stack.","operandParserOffset":16}]"#;
let expected = sample_authoring_meta().abi_encode_validate().unwrap();
let normalized = KnownMeta::AuthoringMetaV1
.normalize(json.as_bytes())
.unwrap();
assert_eq!(normalized, expected);
assert_ne!(normalized, json.as_bytes().to_vec());
}
#[test]
fn test_normalize_authoring_meta_v2_abi_passthrough() {
let mut word = [0u8; 32];
word[..5].copy_from_slice(b"stack");
let abi = authoring_meta_v2_abi(word, "Copies an existing value from the stack.");
assert_eq!(KnownMeta::AuthoringMetaV2.normalize(&abi).unwrap(), abi);
}
#[test]
fn test_normalize_authoring_meta_v2_rejects_arbitrary_bytes() {
assert!(matches!(
KnownMeta::AuthoringMetaV2.normalize(&[0xde, 0xad]),
Err(Error::InvalidInput(_))
));
assert!(matches!(
KnownMeta::AuthoringMetaV2.normalize(b"[]"),
Err(Error::InvalidInput(_))
));
}
#[test]
fn test_normalize_authoring_meta_v2_rejects_non_utf8_word() {
let mut word = [0u8; 32];
word[0] = 0xc3;
word[1] = 0x28;
let abi = authoring_meta_v2_abi(word, "bad word bytes");
assert!(matches!(
KnownMeta::AuthoringMetaV2.normalize(&abi),
Err(Error::InvalidInput(_))
));
}
#[test]
fn test_normalize_authoring_meta_v2_rejects_a_word_outside_the_grammar() {
let mut word = [0u8; 32];
word[..3].copy_from_slice(b"BAD");
let abi = authoring_meta_v2_abi(word, "fine");
assert!(matches!(
KnownMeta::AuthoringMetaV2.normalize(&abi),
Err(Error::InvalidInput(_))
));
}
#[test]
fn test_normalize_default_arm_passthrough() {
let data = b"some dotrain text".to_vec();
assert_eq!(KnownMeta::DotrainV1.normalize(&data).unwrap(), data);
let binary = vec![0xffu8, 0x00, 0x01];
assert_eq!(KnownMeta::RainlangV1.normalize(&binary).unwrap(), binary);
}
}