1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//! Merkle proofs

use serde::{Deserialize, Serialize};
use tendermint_proto::v0_37::crypto::Proof as RawProof;

use crate::{prelude::*, serializers, Hash};

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(try_from = "RawProof", into = "RawProof")]
pub struct Proof {
    // Total number of items.
    pub total: u64,
    // Index of the item to prove.
    pub index: u64,
    // Hash of item value.
    pub leaf_hash: Hash,
    // Hashes from leaf's sibling to a root's child.
    pub aunts: Vec<Hash>,
}

/// Merkle proof defined by the list of ProofOps
/// <https://github.com/tendermint/tendermint/blob/c8483531d8e756f7fbb812db1dd16d841cdf298a/crypto/merkle/merkle.proto#L26>
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ProofOps {
    /// The list of ProofOps
    pub ops: Vec<ProofOp>,
}

/// ProofOp defines an operation used for calculating Merkle root
/// The data could be arbitrary format, providing necessary data
/// for example neighbouring node hash
/// <https://github.com/tendermint/tendermint/blob/c8483531d8e756f7fbb812db1dd16d841cdf298a/crypto/merkle/merkle.proto#L19>
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ProofOp {
    /// Type of the ProofOp
    #[serde(alias = "type")]
    pub field_type: String,
    /// Key of the ProofOp
    #[serde(default, with = "serializers::bytes::base64string")]
    pub key: Vec<u8>,
    /// Actual data
    #[serde(default, with = "serializers::bytes::base64string")]
    pub data: Vec<u8>,
}

// =============================================================================
// Protobuf conversions
// =============================================================================

tendermint_pb_modules! {
    use super::{Proof, ProofOp, ProofOps};
    use crate::{prelude::*, Error};
    use pb::{
        crypto::{Proof as RawProof, ProofOp as RawProofOp, ProofOps as RawProofOps},
    };

    impl Protobuf<RawProof> for Proof {}

    impl TryFrom<RawProof> for Proof {
        type Error = Error;

        fn try_from(message: RawProof) -> Result<Self, Self::Error> {
            Ok(Self {
                total: message
                    .total
                    .try_into()
                    .map_err(Error::negative_proof_total)?,
                index: message
                    .index
                    .try_into()
                    .map_err(Error::negative_proof_index)?,
                leaf_hash: message.leaf_hash.try_into()?,
                aunts: message
                    .aunts
                    .into_iter()
                    .map(TryInto::try_into)
                    .collect::<Result<_, _>>()?,
            })
        }
    }

    impl From<Proof> for RawProof {
        fn from(value: Proof) -> Self {
            Self {
                total: value
                    .total
                    .try_into()
                    .expect("number of items is too large"),
                index: value.index.try_into().expect("index is too large"),
                leaf_hash: value.leaf_hash.into(),
                aunts: value.aunts.into_iter().map(Into::into).collect(),
            }
        }
    }

    impl Protobuf<RawProofOp> for ProofOp {}

    impl TryFrom<RawProofOp> for ProofOp {
        type Error = Error;

        fn try_from(value: RawProofOp) -> Result<Self, Self::Error> {
            Ok(Self {
                field_type: value.r#type,
                key: value.key,
                data: value.data,
            })
        }
    }

    impl From<ProofOp> for RawProofOp {
        fn from(value: ProofOp) -> Self {
            RawProofOp {
                r#type: value.field_type,
                key: value.key,
                data: value.data,
            }
        }
    }

    impl Protobuf<RawProofOps> for ProofOps {}

    impl TryFrom<RawProofOps> for ProofOps {
        type Error = Error;

        fn try_from(value: RawProofOps) -> Result<Self, Self::Error> {
            let ops: Result<Vec<ProofOp>, _> = value.ops.into_iter().map(ProofOp::try_from).collect();

            Ok(Self { ops: ops? })
        }
    }

    impl From<ProofOps> for RawProofOps {
        fn from(value: ProofOps) -> Self {
            let ops: Vec<RawProofOp> = value.ops.into_iter().map(RawProofOp::from).collect();

            RawProofOps { ops }
        }
    }
}

#[cfg(test)]
mod test {
    use super::ProofOps;
    use crate::test::test_serialization_roundtrip;

    #[test]
    fn serialization_roundtrip() {
        let payload = r#"
        {
            "ops": [
                {
                    "type": "iavl:v",
                    "key": "Y29uc2Vuc3VzU3RhdGUvaWJjb25lY2xpZW50LzIy",
                    "data": "8QEK7gEKKAgIEAwYHCIgG9RAkJgHlxNjmyzOW6bUAidhiRSja0x6+GXCVENPG1oKKAgGEAUYFyIgwRns+dJvjf1Zk2BaFrXz8inPbvYHB7xx2HCy9ima5f8KKAgEEAMYFyogOr8EGajEV6fG5fzJ2fAAvVMgRLhdMJTzCPlogl9rxlIKKAgCEAIYFyIgcjzX/a+2bFbnNldpawQqZ+kYhIwz5r4wCUzuu1IFW04aRAoeY29uc2Vuc3VzU3RhdGUvaWJjb25lY2xpZW50LzIyEiAZ1uuG60K4NHJZZMuS9QX6o4eEhica5jIHYwflRiYkDBgX"
                },
                {
                    "type": "multistore",
                    "key": "aWJj",
                    "data": "CvEECjAKBGJhbmsSKAomCIjYAxIg2MEyyonbZButYnvSRkf2bPQg+nqA+Am1MeDxG6F4p1UKLwoDYWNjEigKJgiI2AMSIN2YHczeuXNvyetrSFQpkCcJzfB6PXVCw0i/XShMgPnIChEKB3VwZ3JhZGUSBgoECIjYAwovCgNnb3YSKAomCIjYAxIgYM0TfBli7KxhY4nWgDSDPykhUJwtKFql9RU5l86WinQKLwoDaWJjEigKJgiI2AMSIFp6aJASeInQKF8y824zjmgcFORN6M+ECbgFfJkobKs8CjAKBG1haW4SKAomCIjYAxIgsZzwmLQ7PH1UeZ/vCUSqlQmfgt3CGfoMgJLkUqKCv0EKMwoHc3Rha2luZxIoCiYIiNgDEiCiBZoBLyDGj5euy3n33ik+SpqYK9eB5xbI+iY8ycYVbwo0CghzbGFzaGluZxIoCiYIiNgDEiAJz3gEYuIhdensHU3b5qH5ons2quepd6EaRgCHXab6PQoyCgZzdXBwbHkSKAomCIjYAxIglWLA5/THPTiTxAlaLHOBYFIzEJTmKPznItUwAc8zD+AKEgoIZXZpZGVuY2USBgoECIjYAwowCgRtaW50EigKJgiI2AMSIMS8dZ1j8F6JVVv+hB1rHBZC+gIFJxHan2hM8qDC64n/CjIKBnBhcmFtcxIoCiYIiNgDEiB8VIzExUHX+SvHZFz/P9NM9THnw/gTDDLVReuZX8htLgo4CgxkaXN0cmlidXRpb24SKAomCIjYAxIg3u/Nd4L+8LT8OXJCh14o8PHIJ/GLQwsmE7KYIl1GdSYKEgoIdHJhbnNmZXISBgoECIjYAw=="
                }
            ]
        }"#;
        test_serialization_roundtrip::<ProofOps>(payload);
    }
}