From 32e0b2e68a2d50c05b2afee3db963f1af1ceeac2 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Wed, 6 Nov 2024 10:11:19 -0800 Subject: [PATCH] add v2 types lint: allow large enum variant temp --- .rustfmt.toml | 2 +- sia/src/signing.rs | 6 + sia/src/transactions.rs | 795 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 789 insertions(+), 14 deletions(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index 0c205e8..9768192 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,4 +1,4 @@ newline_style="Unix" reorder_imports=true # only supported in nightly -imports_granularity="Module" \ No newline at end of file +imports_granularity="Module" diff --git a/sia/src/signing.rs b/sia/src/signing.rs index c576a12..641eb98 100644 --- a/sia/src/signing.rs +++ b/sia/src/signing.rs @@ -167,6 +167,12 @@ impl AsRef<[u8; 64]> for Signature { } } +impl From<[u8; 64]> for Signature { + fn from(buf: [u8; 64]) -> Self { + Signature(buf) + } +} + impl fmt::Display for Signature { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", hex::encode(self.0)) diff --git a/sia/src/transactions.rs b/sia/src/transactions.rs index 63b1869..1b69b97 100644 --- a/sia/src/transactions.rs +++ b/sia/src/transactions.rs @@ -1,20 +1,24 @@ use crate::encoding::{ - SiaDecodable, SiaDecode, SiaEncodable, SiaEncode, V1SiaDecodable, V1SiaDecode, V1SiaEncodable, - V1SiaEncode, + self, SiaDecodable, SiaDecode, SiaEncodable, SiaEncode, V1SiaDecodable, V1SiaDecode, + V1SiaEncodable, V1SiaEncode, }; -use crate::signing::{PrivateKey, SigningState}; +use crate::signing::{PrivateKey, PublicKey, Signature, SigningState}; use crate::specifier::{specifier, Specifier}; +use crate::spendpolicy::SatisfiedPolicy; use crate::unlock_conditions::UnlockConditions; -use crate::{encoding, Address, Currency, Hash256, Leaf}; +use crate::{Address, BlockID, ChainIndex, Currency, Hash256, Leaf}; use blake2b_simd::Params; +use serde::de::{Error, MapAccess, Visitor}; +use serde::ser::SerializeStruct; use serde::{Deserialize, Serialize}; +use serde_json::json; pub type SiacoinOutputID = Hash256; pub type SiafundOutputID = Hash256; pub type FileContractID = Hash256; pub type TransactionID = Hash256; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] +#[derive(Debug, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] #[serde(rename_all = "camelCase")] pub struct SiacoinInput { #[serde(rename = "parentID")] @@ -23,7 +27,7 @@ pub struct SiacoinInput { } #[derive( - Debug, Clone, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode, V1SiaEncode, V1SiaDecode, + Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode, V1SiaEncode, V1SiaDecode, )] #[serde(rename_all = "camelCase")] pub struct SiacoinOutput { @@ -31,7 +35,7 @@ pub struct SiacoinOutput { pub address: Address, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] +#[derive(Debug, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] #[serde(rename_all = "camelCase")] pub struct SiafundInput { #[serde(rename = "parentID")] @@ -40,7 +44,7 @@ pub struct SiafundInput { pub claim_address: Address, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] #[serde(rename_all = "camelCase")] pub struct SiafundOutput { pub value: u64, @@ -51,7 +55,7 @@ impl V1SiaEncodable for SiafundOutput { fn encode_v1(&self, w: &mut W) -> encoding::Result<()> { Currency::new(self.value as u128).encode_v1(w)?; self.address.encode_v1(w)?; - Currency::new(0).encode_v1(w) // siad encodes a "claim start," but transactions its an error if it's non-zero. + Currency::new(0).encode_v1(w) // siad encodes a "claim start," but its an error if it's non-zero. } } @@ -68,7 +72,7 @@ impl V1SiaDecodable for SiafundOutput { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] +#[derive(Debug, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] #[serde(rename_all = "camelCase")] pub struct FileContract { #[serde(rename = "filesize")] @@ -83,7 +87,7 @@ pub struct FileContract { pub revision_number: u64, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] +#[derive(Debug, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] #[serde(rename_all = "camelCase")] pub struct FileContractRevision { #[serde(rename = "parentID")] @@ -100,7 +104,7 @@ pub struct FileContractRevision { pub unlock_hash: Hash256, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] +#[derive(Debug, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] #[serde(rename_all = "camelCase")] pub struct StorageProof { #[serde(rename = "parentID")] @@ -134,7 +138,7 @@ impl CoveredFields { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] +#[derive(Debug, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)] #[serde(rename_all = "camelCase")] pub struct TransactionSignature { #[serde(rename = "parentID")] @@ -383,6 +387,368 @@ impl Transaction { } } +/// A V2FileContract is a storage agreement between a renter and a host. It +/// consists of a bidirectional payment channel that resolves as either "valid" +/// or "missed" depending on whether a valid StorageProof is submitted for the +/// contract. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct V2FileContract { + pub capacity: u64, + pub filesize: u64, + pub file_merkle_root: Hash256, + pub proof_height: u64, + pub expiration_height: u64, + pub renter_output: SiacoinOutput, + pub host_output: SiacoinOutput, + pub missed_host_value: Currency, + pub total_collateral: Currency, + pub renter_public_key: PublicKey, + pub host_public_key: PublicKey, + pub revision_number: u64, + + pub renter_signature: Signature, + pub host_signature: Signature, +} + +/// A V2FileContractRevision updates the state of an existing file contract. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct V2FileContractRevision { + pub parent: V2FileContractElement, + pub revision: V2FileContract, +} + +/// A V2FileContractRenewal renews a file contract with optional rollover +/// of any unspent funds. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct V2FileContractRenewal { + pub final_revision: V2FileContract, + pub new_contract: V2FileContract, + pub renter_rollover: Currency, + pub host_rollover: Currency, + + // signatures cover above fields + pub renter_signature: Signature, + pub host_signature: Signature, +} + +/// A V2StorageProof asserts the presence of a randomly-selected leaf within the +/// Merkle tree of a V2FileContract's data. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct V2StorageProof { + // Selecting the leaf requires a source of unpredictable entropy; we use the + // ID of the block at the contract's ProofHeight. The storage proof thus + // includes a proof that this ID is the correct ancestor. + // + // During validation, it is imperative to check that ProofIndex.Height + // matches the ProofHeight field of the contract's final revision; + // otherwise, the prover could use any ProofIndex, giving them control over + // the leaf index. + pub proof_index: ChainIndexElement, + // The leaf is always 64 bytes, extended with zeros if necessary. + pub leaf: Leaf, + pub proof: Vec, +} + +/// A V2ContractResolution closes a v2 file contract's payment channel. There +/// are four ways a contract can be resolved: +/// +/// 1. The renter can finalize the contract's current state, preventing further +/// revisions and immediately creating its outputs. +/// +/// 2. The renter and host can jointly renew the contract. The old contract is +/// finalized, and a portion of its funds are "rolled over" into a new contract. +/// +/// 3. The host can submit a storage proof, asserting that it has faithfully +/// stored the contract data for the agreed-upon duration. Typically, a storage +/// proof is only required if the renter is unable or unwilling to sign a +/// finalization or renewal. A storage proof can only be submitted after the +/// contract's ProofHeight; this allows the renter (or host) to broadcast the +/// latest contract revision prior to the proof. +/// +/// 4. Lastly, anyone can submit a contract expiration. Typically, an expiration +/// is only required if the host is unable or unwilling to sign a finalization or +/// renewal. An expiration can only be submitted after the contract's +/// ExpirationHeight; this gives the host a reasonable window of time after the +/// ProofHeight in which to submit a storage proof. +/// +/// Once a contract has been resolved, it cannot be altered or resolved again. +/// When a contract is resolved, its RenterOutput and HostOutput are created +/// immediately (though they will not be spendable until their timelock expires). +/// However, if the contract is resolved via an expiration, the HostOutput will +/// have value equal to MissedHostValue; in other words, the host forfeits its +/// collateral. This is considered a "missed" resolution; all other resolution +/// types are "valid." As a special case, the expiration of an empty contract is +/// considered valid, reflecting the fact that the host has not failed to perform +/// any duty. +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::large_enum_variant)] +pub enum V2ContractResolution { + Finalization(Signature), + Renewal(V2FileContractRenewal), + StorageProof(V2StorageProof), + Expiration(), +} + +/// A V2FileContractResolution closes a v2 file contract's payment channel. +#[derive(Debug, PartialEq)] +pub struct V2FileContractResolution { + pub parent: V2FileContractElement, + pub resolution: V2ContractResolution, +} + +impl SiaEncodable for V2FileContractResolution { + fn encode(&self, w: &mut W) -> encoding::Result<()> { + self.parent.encode(w)?; + match &self.resolution { + V2ContractResolution::Renewal(renewal) => { + 0u8.encode(w)?; + renewal.encode(w) + } + V2ContractResolution::StorageProof(proof) => { + 1u8.encode(w)?; + proof.encode(w) + } + V2ContractResolution::Finalization(sig) => { + 2u8.encode(w)?; + sig.encode(w) + } + V2ContractResolution::Expiration() => 3u8.encode(w), + } + } +} + +impl SiaDecodable for V2FileContractResolution { + fn decode(r: &mut R) -> encoding::Result { + let parent = V2FileContractElement::decode(r)?; + let resolution = match u8::decode(r)? { + 0 => V2ContractResolution::Renewal(V2FileContractRenewal::decode(r)?), + 1 => V2ContractResolution::StorageProof(V2StorageProof::decode(r)?), + 2 => V2ContractResolution::Finalization(Signature::decode(r)?), + 3 => V2ContractResolution::Expiration(), + _ => { + return Err(encoding::Error::Custom( + "invalid contract resolution type".to_string(), + )) + } + }; + Ok(V2FileContractResolution { parent, resolution }) + } +} + +impl Serialize for V2FileContractResolution { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_struct("V2FileContractResolution", 3)?; + state.serialize_field("parent", &self.parent)?; + state.serialize_field( + "type", + &match &self.resolution { + V2ContractResolution::Renewal(_) => "renewal", + V2ContractResolution::StorageProof(_) => "storageProof", + V2ContractResolution::Finalization(_) => "finalization", + V2ContractResolution::Expiration() => "expiration", + }, + )?; + let resolution = match &self.resolution { + V2ContractResolution::Finalization(sig) => { + serde_json::to_value(sig).map_err(serde::ser::Error::custom)? + } + V2ContractResolution::Renewal(renewal) => { + serde_json::to_value(renewal).map_err(serde::ser::Error::custom)? + } + V2ContractResolution::StorageProof(proof) => { + serde_json::to_value(proof).map_err(serde::ser::Error::custom)? + } + V2ContractResolution::Expiration() => json!({}), + }; + state.serialize_field("resolution", &resolution)?; + state.end() + } +} + +impl<'de> Deserialize<'de> for V2FileContractResolution { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct V2FileContractResolutionVisitor; + + impl<'de> Visitor<'de> for V2FileContractResolutionVisitor { + type Value = V2FileContractResolution; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("struct V2FileContractResolution") + } + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + let mut parent: Option = None; + let mut resolution_type: Option = None; + let mut resolution_value: Option = None; + + while let Some(key) = map.next_key::()? { + match key.as_str() { + "parent" => parent = Some(map.next_value()?), + "type" => resolution_type = Some(map.next_value()?), + "resolution" => resolution_value = Some(map.next_value()?), + _ => { + return Err(serde::de::Error::unknown_field( + key.as_str(), + &["parent", "type", "resolution"], + )); + } + } + } + + let parent = parent.ok_or_else(|| serde::de::Error::missing_field("parent"))?; + let resolution_type = + resolution_type.ok_or_else(|| serde::de::Error::missing_field("type"))?; + let resolution_value = resolution_value + .ok_or_else(|| serde::de::Error::missing_field("resolution"))?; + + let resolution = match resolution_type.as_str() { + "finalization" => V2ContractResolution::Finalization( + serde_json::from_value(resolution_value).map_err(Error::custom)?, + ), + "renewal" => V2ContractResolution::Renewal( + serde_json::from_value(resolution_value).map_err(Error::custom)?, + ), + "storageProof" => V2ContractResolution::StorageProof( + serde_json::from_value(resolution_value).map_err(Error::custom)?, + ), + "expiration" => V2ContractResolution::Expiration(), + _ => return Err(serde::de::Error::custom("invalid contract resolution type")), + }; + + Ok(V2FileContractResolution { parent, resolution }) + } + } + deserializer.deserialize_struct( + "V2FileContractResolution", + &["parent", "type", "resolution"], + V2FileContractResolutionVisitor, + ) + } +} + +/// An Attestation associates a key-value pair with an identity. For example, +/// hosts attest to their network address by setting Key to "HostAnnouncement" +/// and Value to their address, thereby allowing renters to discover them. +/// Generally, an attestation for a particular key is considered to overwrite any +/// previous attestations with the same key. (This allows hosts to announce a new +/// network address, for example.) +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct Attestation { + pub public_key: PublicKey, + pub key: String, + pub value: Vec, + + pub signature: Signature, +} + +/// An AttestationID uniquely identifies an attestation. +type AttestationID = Hash256; + +/// A StateElement is a generic element within the state accumulator. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct StateElement { + pub leaf_index: u64, + pub merkle_proof: Vec, +} + +/// A SiacoinElement is a record of a Siacoin UTXO within the state accumulator. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct SiacoinElement { + pub state_element: StateElement, + pub id: SiacoinOutputID, + pub siacoin_output: SiacoinOutput, + pub maturity_height: u64, +} + +/// A SiafundElement is a record of a Siafund UTXO within the state accumulator. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct SiafundElement { + pub state_element: StateElement, + pub id: SiafundOutputID, + pub siafund_output: SiafundOutput, + pub claim_start: Currency, +} + +/// A V2FileContractElement is a record of a FileContract within the state +/// accumulator. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct V2FileContractElement { + pub state_element: StateElement, + pub id: FileContractID, + pub v2_file_contract: V2FileContract, +} + +/// A ChainIndexElement is a record of a ChainIndex within the state accumulator. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct ChainIndexElement { + pub state_element: StateElement, + pub id: BlockID, + pub chain_index: ChainIndex, +} + +/// An AttestationElement is a record of an Attestation within the state +/// accumulator. +pub struct AttestationElement { + pub state_element: StateElement, + pub id: AttestationID, + pub attestation: Attestation, +} + +/// A V2SiacoinInput represents a Siacoin UTXO that is being spent in a v2 +/// transaction. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct V2SiacoinInput { + pub parent: SiacoinElement, + pub satisfied_policy: SatisfiedPolicy, +} + +/// A V2SiafundInput represents a Siafund UTXO that is being spent in a v2 +/// transaction. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct V2SiafundInput { + pub parent: SiafundElement, + pub claim_address: Address, + pub satisfied_policy: SatisfiedPolicy, +} + +/// A V2Transaction effects a change of blockchain state. +#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)] +#[serde(rename_all = "camelCase")] +pub struct V2Transaction { + pub siacoin_inputs: Vec, + pub siacoin_outputs: Vec, + pub siafund_inputs: Vec, + pub siafund_outputs: Vec, + pub file_contracts: Vec, + pub file_contract_revisions: Vec, + pub file_contract_resolutions: Vec, + pub arbitrary_data: Vec>, + pub new_foundation_address: Option
, + pub miner_fee: Currency, +} + // Create a helper module for base64 serialization mod base64 { use base64::engine::general_purpose::STANDARD; @@ -935,4 +1301,407 @@ mod tests { let json_str = "{\"siacoinInputs\":[],\"siacoinOutputs\":[],\"fileContracts\":[],\"fileContractRevisions\":[],\"storageProofs\":[],\"siafundInputs\":[],\"siafundOutputs\":[],\"minerFees\":[],\"arbitraryData\":[],\"signatures\":[]}"; test_serialize_json(&transaction, json_str); } + + #[test] + fn test_serialize_siacoin_element() { + let se = SiacoinElement { + id: SiacoinOutputID::default(), + siacoin_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + state_element: StateElement { + leaf_index: 0, + merkle_proof: vec![Hash256::default()], + }, + maturity_height: 0, + }; + + let binary_str = "00000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + test_serialize(&se, binary_str); + + let json_str = "{\"stateElement\":{\"leafIndex\":0,\"merkleProof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"]},\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"siacoinOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"maturityHeight\":0}"; + test_serialize_json(&se, json_str); + } + + #[test] + fn test_serialize_siafund_element() { + let se = SiafundElement { + id: SiafundOutputID::default(), + state_element: StateElement { + leaf_index: 0, + merkle_proof: vec![Hash256::default()], + }, + siafund_output: SiafundOutput { + value: 0, + address: Address::new([0; 32]), + }, + claim_start: Currency::new(0), + }; + + let binary_str = "00000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + test_serialize(&se, binary_str); + + let json_str = "{\"stateElement\":{\"leafIndex\":0,\"merkleProof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"]},\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"siafundOutput\":{\"value\":0,\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"claimStart\":\"0\"}"; + test_serialize_json(&se, json_str); + } + + #[test] + fn test_serialize_v2_file_contract_element() { + let fce = V2FileContractElement { + id: FileContractID::default(), + state_element: StateElement { + leaf_index: 0, + merkle_proof: vec![Hash256::default()], + }, + v2_file_contract: V2FileContract { + capacity: 0, + filesize: 0, + file_merkle_root: Hash256::default(), + proof_height: 0, + expiration_height: 0, + renter_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + host_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + missed_host_value: Currency::new(0), + total_collateral: Currency::new(0), + host_public_key: PublicKey::new([0; 32]), + renter_public_key: PublicKey::new([0; 32]), + revision_number: 0, + + host_signature: Signature::new([0; 64]), + renter_signature: Signature::new([0; 64]), + }, + }; + + let binary_str = "00000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + test_serialize(&fce, binary_str); + + let json_str = "{\"stateElement\":{\"leafIndex\":0,\"merkleProof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"]},\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"v2FileContract\":{\"capacity\":0,\"filesize\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"proofHeight\":0,\"expirationHeight\":0,\"renterOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hostOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"missedHostValue\":\"0\",\"totalCollateral\":\"0\",\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}}"; + test_serialize_json(&fce, json_str); + } + + #[test] + fn test_serialize_v2_file_contract() { + let fc = V2FileContract { + capacity: 0, + filesize: 0, + file_merkle_root: Hash256::default(), + proof_height: 0, + expiration_height: 0, + renter_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + host_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + missed_host_value: Currency::new(0), + total_collateral: Currency::new(0), + host_public_key: PublicKey::new([0; 32]), + renter_public_key: PublicKey::new([0; 32]), + revision_number: 0, + + host_signature: Signature::new([0; 64]), + renter_signature: Signature::new([0; 64]), + }; + + let binary_str = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + test_serialize(&fc, binary_str); + + let json_str = "{\"capacity\":0,\"filesize\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"proofHeight\":0,\"expirationHeight\":0,\"renterOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hostOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"missedHostValue\":\"0\",\"totalCollateral\":\"0\",\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}"; + test_serialize_json(&fc, json_str); + } + + #[test] + fn test_serialize_v2_file_contract_revision() { + let fcr = V2FileContractRevision { + parent: V2FileContractElement { + id: FileContractID::default(), + state_element: StateElement { + leaf_index: 0, + merkle_proof: vec![Hash256::default()], + }, + v2_file_contract: V2FileContract { + capacity: 0, + filesize: 0, + file_merkle_root: Hash256::default(), + proof_height: 0, + expiration_height: 0, + renter_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + host_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + missed_host_value: Currency::new(0), + total_collateral: Currency::new(0), + host_public_key: PublicKey::new([0; 32]), + renter_public_key: PublicKey::new([0; 32]), + revision_number: 0, + + host_signature: Signature::new([0; 64]), + renter_signature: Signature::new([0; 64]), + }, + }, + revision: V2FileContract { + capacity: 0, + filesize: 0, + file_merkle_root: Hash256::default(), + proof_height: 0, + expiration_height: 0, + renter_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + host_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + missed_host_value: Currency::new(0), + total_collateral: Currency::new(0), + host_public_key: PublicKey::new([0; 32]), + renter_public_key: PublicKey::new([0; 32]), + revision_number: 0, + + host_signature: Signature::new([0; 64]), + renter_signature: Signature::new([0; 64]), + }, + }; + + let binary_str = "000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + test_serialize(&fcr, binary_str); + + let json_str = "{\"parent\":{\"stateElement\":{\"leafIndex\":0,\"merkleProof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"]},\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"v2FileContract\":{\"capacity\":0,\"filesize\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"proofHeight\":0,\"expirationHeight\":0,\"renterOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hostOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"missedHostValue\":\"0\",\"totalCollateral\":\"0\",\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}},\"revision\":{\"capacity\":0,\"filesize\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"proofHeight\":0,\"expirationHeight\":0,\"renterOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hostOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"missedHostValue\":\"0\",\"totalCollateral\":\"0\",\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}}"; + test_serialize_json(&fcr, json_str); + } + + #[test] + fn test_serialize_v2_file_contract_renewal() { + let fcr = V2FileContractRenewal { + new_contract: V2FileContract { + capacity: 0, + filesize: 0, + file_merkle_root: Hash256::default(), + proof_height: 0, + expiration_height: 0, + renter_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + host_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + missed_host_value: Currency::new(0), + total_collateral: Currency::new(0), + host_public_key: PublicKey::new([0; 32]), + renter_public_key: PublicKey::new([0; 32]), + revision_number: 0, + + host_signature: Signature::new([0; 64]), + renter_signature: Signature::new([0; 64]), + }, + final_revision: V2FileContract { + capacity: 0, + filesize: 0, + file_merkle_root: Hash256::default(), + proof_height: 0, + expiration_height: 0, + renter_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + host_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + missed_host_value: Currency::new(0), + total_collateral: Currency::new(0), + host_public_key: PublicKey::new([0; 32]), + renter_public_key: PublicKey::new([0; 32]), + revision_number: 0, + + host_signature: Signature::new([0; 64]), + renter_signature: Signature::new([0; 64]), + }, + renter_rollover: Currency::new(0), + host_rollover: Currency::new(0), + renter_signature: Signature::new([0u8; 64]), + host_signature: Signature::new([0u8; 64]), + }; + + let binary_str = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + test_serialize(&fcr, binary_str); + + let json_str = "{\"finalRevision\":{\"capacity\":0,\"filesize\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"proofHeight\":0,\"expirationHeight\":0,\"renterOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hostOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"missedHostValue\":\"0\",\"totalCollateral\":\"0\",\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"},\"newContract\":{\"capacity\":0,\"filesize\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"proofHeight\":0,\"expirationHeight\":0,\"renterOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hostOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"missedHostValue\":\"0\",\"totalCollateral\":\"0\",\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"},\"renterRollover\":\"0\",\"hostRollover\":\"0\",\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}"; + test_serialize_json(&fcr, json_str); + } + + #[test] + fn test_serialize_v2_storage_proof() { + let sp = V2StorageProof { + proof_index: ChainIndexElement { + id: BlockID::default(), + chain_index: ChainIndex { + id: BlockID::default(), + height: 0, + }, + state_element: StateElement { + leaf_index: 0, + merkle_proof: vec![Hash256::default()], + }, + }, + leaf: [3u8; 64].into(), + proof: vec![Hash256::default()], + }; + + let binary_str = "0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030301000000000000000000000000000000000000000000000000000000000000000000000000000000"; + test_serialize(&sp, binary_str); + + let json_str = "{\"proofIndex\":{\"stateElement\":{\"leafIndex\":0,\"merkleProof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"]},\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"chainIndex\":{\"height\":0,\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\"}},\"leaf\":\"03030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303\",\"proof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"]}"; + test_serialize_json(&sp, json_str); + } + + #[test] + fn test_serialize_v2_file_contract_resolution() { + struct TestCase { + resolution: V2ContractResolution, + binary_str: String, + json_str: String, + } + let test_cases = vec![ + TestCase{ + resolution: V2ContractResolution::Renewal(V2FileContractRenewal { + new_contract: V2FileContract { + capacity: 0, + filesize: 0, + file_merkle_root: Hash256::default(), + proof_height: 0, + expiration_height: 0, + renter_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + host_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + missed_host_value: Currency::new(0), + total_collateral: Currency::new(0), + host_public_key: PublicKey::new([0; 32]), + renter_public_key: PublicKey::new([0; 32]), + revision_number: 0, + + host_signature: Signature::new([0; 64]), + renter_signature: Signature::new([0; 64]), + }, + final_revision: V2FileContract { + capacity: 0, + filesize: 0, + file_merkle_root: Hash256::default(), + proof_height: 0, + expiration_height: 0, + renter_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + host_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + missed_host_value: Currency::new(0), + total_collateral: Currency::new(0), + host_public_key: PublicKey::new([0; 32]), + renter_public_key: PublicKey::new([0; 32]), + revision_number: 0, + + host_signature: Signature::new([0; 64]), + renter_signature: Signature::new([0; 64]), + }, + renter_rollover: Currency::new(0), + host_rollover: Currency::new(0), + renter_signature: Signature::new([0u8; 64]), + host_signature: Signature::new([0u8; 64]), + }), + binary_str: "00000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".to_string(), + json_str: "{\"parent\":{\"stateElement\":{\"leafIndex\":0,\"merkleProof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"]},\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"v2FileContract\":{\"capacity\":0,\"filesize\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"proofHeight\":0,\"expirationHeight\":0,\"renterOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hostOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"missedHostValue\":\"0\",\"totalCollateral\":\"0\",\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}},\"type\":\"renewal\",\"resolution\":{\"finalRevision\":{\"capacity\":0,\"expirationHeight\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"filesize\":0,\"hostOutput\":{\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\",\"value\":\"0\"},\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"missedHostValue\":\"0\",\"proofHeight\":0,\"renterOutput\":{\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\",\"value\":\"0\"},\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"totalCollateral\":\"0\"},\"hostRollover\":\"0\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"newContract\":{\"capacity\":0,\"expirationHeight\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"filesize\":0,\"hostOutput\":{\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\",\"value\":\"0\"},\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"missedHostValue\":\"0\",\"proofHeight\":0,\"renterOutput\":{\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\",\"value\":\"0\"},\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"totalCollateral\":\"0\"},\"renterRollover\":\"0\",\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}}".to_string(), + }, + TestCase{ + resolution: V2ContractResolution::StorageProof(V2StorageProof{ + proof_index: ChainIndexElement { + id: BlockID::default(), + chain_index: ChainIndex { + id: BlockID::default(), + height: 0, + }, + state_element: StateElement { + leaf_index: 0, + merkle_proof: vec![Hash256::default()], + }, + }, + leaf: [0u8; 64].into(), + proof: vec![Hash256::default()], + }), + binary_str: "00000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000".to_string(), + json_str: "{\"parent\":{\"stateElement\":{\"leafIndex\":0,\"merkleProof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"]},\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"v2FileContract\":{\"capacity\":0,\"filesize\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"proofHeight\":0,\"expirationHeight\":0,\"renterOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hostOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"missedHostValue\":\"0\",\"totalCollateral\":\"0\",\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}},\"type\":\"storageProof\",\"resolution\":{\"leaf\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"proof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"],\"proofIndex\":{\"chainIndex\":{\"height\":0,\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\"},\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"stateElement\":{\"leafIndex\":0,\"merkleProof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"]}}}}".to_string(), + }, + TestCase{ + resolution: V2ContractResolution::Finalization([0u8;64].into()), + binary_str: "000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".to_string(), + json_str: "{\"parent\":{\"stateElement\":{\"leafIndex\":0,\"merkleProof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"]},\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"v2FileContract\":{\"capacity\":0,\"filesize\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"proofHeight\":0,\"expirationHeight\":0,\"renterOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hostOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"missedHostValue\":\"0\",\"totalCollateral\":\"0\",\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}},\"type\":\"finalization\",\"resolution\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}".to_string(), + }, + TestCase{ + resolution: V2ContractResolution::Expiration(), + binary_str: "0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003".to_string(), + json_str: "{\"parent\":{\"stateElement\":{\"leafIndex\":0,\"merkleProof\":[\"0000000000000000000000000000000000000000000000000000000000000000\"]},\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"v2FileContract\":{\"capacity\":0,\"filesize\":0,\"fileMerkleRoot\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"proofHeight\":0,\"expirationHeight\":0,\"renterOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hostOutput\":{\"value\":\"0\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"missedHostValue\":\"0\",\"totalCollateral\":\"0\",\"renterPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"hostPublicKey\":\"ed25519:0000000000000000000000000000000000000000000000000000000000000000\",\"revisionNumber\":0,\"renterSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"hostSignature\":\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}},\"type\":\"expiration\",\"resolution\":{}}".to_string(), + } + ]; + for tc in test_cases { + let fcr = V2FileContractResolution { + parent: V2FileContractElement { + id: FileContractID::default(), + state_element: StateElement { + leaf_index: 0, + merkle_proof: vec![Hash256::default()], + }, + v2_file_contract: V2FileContract { + capacity: 0, + filesize: 0, + file_merkle_root: Hash256::default(), + proof_height: 0, + expiration_height: 0, + renter_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + host_output: SiacoinOutput { + value: Currency::new(0), + address: Address::new([0; 32]), + }, + missed_host_value: Currency::new(0), + total_collateral: Currency::new(0), + host_public_key: PublicKey::new([0; 32]), + renter_public_key: PublicKey::new([0; 32]), + revision_number: 0, + + host_signature: Signature::new([0; 64]), + renter_signature: Signature::new([0; 64]), + }, + }, + resolution: tc.resolution, + }; + + test_serialize(&fcr, tc.binary_str.as_str()); + test_serialize_json(&fcr, tc.json_str.as_str()); + } + } }