use super::*;
impl<N: Network> Serialize for Transaction<N> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match serializer.is_human_readable() {
true => match self {
Self::Deploy(id, deployment, additional_fee) => {
let mut transaction = serializer.serialize_struct("Transaction", 4)?;
transaction.serialize_field("type", "deploy")?;
transaction.serialize_field("id", &id)?;
transaction.serialize_field("deployment", &deployment)?;
transaction.serialize_field("additional_fee", &additional_fee)?;
transaction.end()
}
Self::Execute(id, execution, additional_fee) => {
let mut transaction = serializer.serialize_struct("Transaction", 4)?;
transaction.serialize_field("type", "execute")?;
transaction.serialize_field("id", &id)?;
transaction.serialize_field("execution", &execution)?;
if let Some(additional_fee) = additional_fee {
transaction.serialize_field("additional_fee", &additional_fee)?;
}
transaction.end()
}
},
false => ToBytesSerializer::serialize_with_size_encoding(self, serializer),
}
}
}
impl<'de, N: Network> Deserialize<'de> for Transaction<N> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
match deserializer.is_human_readable() {
true => {
let transaction = serde_json::Value::deserialize(deserializer)?;
let id: N::TransactionID =
serde_json::from_value(transaction["id"].clone()).map_err(de::Error::custom)?;
let transaction = match transaction["type"].as_str() {
Some("deploy") => {
let deployment =
serde_json::from_value(transaction["deployment"].clone()).map_err(de::Error::custom)?;
let additional_fee =
serde_json::from_value(transaction["additional_fee"].clone()).map_err(de::Error::custom)?;
Transaction::from_deployment(deployment, additional_fee).map_err(de::Error::custom)?
}
Some("execute") => {
let execution =
serde_json::from_value(transaction["execution"].clone()).map_err(de::Error::custom)?;
let additional_fee = match transaction["additional_fee"].as_str() {
Some(additional_fee) => {
Some(serde_json::from_str(additional_fee).map_err(de::Error::custom)?)
}
None => None,
};
Transaction::from_execution(execution, additional_fee).map_err(de::Error::custom)?
}
_ => return Err(de::Error::custom("Invalid transaction type")),
};
match id == transaction.id() {
true => Ok(transaction),
false => {
Err(error("Mismatching transaction ID, possible data corruption")).map_err(de::Error::custom)
}
}
}
false => FromBytesDeserializer::<Self>::deserialize_with_size_encoding(deserializer, "transaction"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_serde_json() -> Result<()> {
for expected in [
crate::ledger::vm::test_helpers::sample_deployment_transaction(),
crate::ledger::vm::test_helpers::sample_execution_transaction(),
]
.into_iter()
{
let expected_string = &expected.to_string();
let candidate_string = serde_json::to_string(&expected)?;
assert_eq!(expected, Transaction::from_str(expected_string)?);
assert_eq!(expected, serde_json::from_str(&candidate_string)?);
}
Ok(())
}
#[test]
fn test_bincode() -> Result<()> {
for expected in [
crate::ledger::vm::test_helpers::sample_deployment_transaction(),
crate::ledger::vm::test_helpers::sample_execution_transaction(),
]
.into_iter()
{
let expected_bytes = expected.to_bytes_le()?;
let expected_bytes_with_size_encoding = bincode::serialize(&expected)?;
assert_eq!(&expected_bytes[..], &expected_bytes_with_size_encoding[8..]);
assert_eq!(expected, Transaction::read_le(&expected_bytes[..])?);
assert_eq!(expected, bincode::deserialize(&expected_bytes_with_size_encoding[..])?);
}
Ok(())
}
}