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, owner, deployment, fee) => {
let mut transaction = serializer.serialize_struct("Transaction", 5)?;
transaction.serialize_field("type", "deploy")?;
transaction.serialize_field("id", &id)?;
transaction.serialize_field("owner", &owner)?;
transaction.serialize_field("deployment", &deployment)?;
transaction.serialize_field("fee", &fee)?;
transaction.end()
}
Self::Execute(id, execution, fee) => {
let mut transaction = serializer.serialize_struct("Transaction", 3 + fee.is_some() as usize)?;
transaction.serialize_field("type", "execute")?;
transaction.serialize_field("id", &id)?;
transaction.serialize_field("execution", &execution)?;
if let Some(fee) = fee {
transaction.serialize_field("fee", &fee)?;
}
transaction.end()
}
Self::Fee(id, fee) => {
let mut transaction = serializer.serialize_struct("Transaction", 3)?;
transaction.serialize_field("type", "fee")?;
transaction.serialize_field("id", &id)?;
transaction.serialize_field("fee", &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 mut transaction = serde_json::Value::deserialize(deserializer)?;
let id: N::TransactionID = DeserializeExt::take_from_value::<D>(&mut transaction, "id")?;
let transaction = match transaction
.get("type")
.ok_or_else(|| de::Error::custom("The \"type\" field is missing"))?
.as_str()
{
Some("deploy") => {
let owner = DeserializeExt::take_from_value::<D>(&mut transaction, "owner")?;
let deployment = DeserializeExt::take_from_value::<D>(&mut transaction, "deployment")?;
let fee = DeserializeExt::take_from_value::<D>(&mut transaction, "fee")?;
Transaction::from_deployment(owner, deployment, fee).map_err(de::Error::custom)?
}
Some("execute") => {
let execution = DeserializeExt::take_from_value::<D>(&mut transaction, "execution")?;
let fee = serde_json::from_value(
transaction.get_mut("fee").unwrap_or(&mut serde_json::Value::Null).take(),
)
.map_err(de::Error::custom)?;
Transaction::from_execution(execution, fee).map_err(de::Error::custom)?
}
Some("fee") => {
let fee = DeserializeExt::take_from_value::<D>(&mut transaction, "fee")?;
Transaction::from_fee(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<()> {
let rng = &mut TestRng::default();
for expected in [
crate::transaction::test_helpers::sample_deployment_transaction(true, rng),
crate::transaction::test_helpers::sample_deployment_transaction(false, rng),
crate::transaction::test_helpers::sample_execution_transaction_with_fee(true, rng),
crate::transaction::test_helpers::sample_execution_transaction_with_fee(false, rng),
]
.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<()> {
let rng = &mut TestRng::default();
for expected in [
crate::transaction::test_helpers::sample_deployment_transaction(true, rng),
crate::transaction::test_helpers::sample_deployment_transaction(false, rng),
crate::transaction::test_helpers::sample_execution_transaction_with_fee(true, rng),
crate::transaction::test_helpers::sample_execution_transaction_with_fee(false, rng),
]
.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(())
}
}