trustchain_ion/
lib.rs

1//! Trustchain implementation for [ION](https://identity.foundation/ion/) DID method.
2pub mod attest;
3pub mod attestor;
4pub mod commitment;
5pub mod config;
6pub mod controller;
7pub mod create;
8pub mod data;
9pub mod ion;
10pub mod mnemonic;
11pub mod resolver;
12pub mod root;
13pub mod sidetree;
14pub mod utils;
15pub mod verifier;
16
17use crate::ion::IONTest as ION;
18use crate::resolver::HTTPTrustchainResolver;
19use did_ion::sidetree::HTTPSidetreeDIDResolver;
20use serde::{Deserialize, Serialize};
21use std::string::FromUtf8Error;
22use std::{io, num::ParseIntError};
23use thiserror::Error;
24
25/// Type alias for URL
26// TODO [#126]: remove in favour of new type pattern (e.g. URL(String)) or use https://crates.io/crates/url
27// for better handling of URLs.
28pub type URL = String;
29
30/// Full client zero sized type for marker in `TrustchainVerifier`.
31pub struct FullClient;
32/// Light client zero sized type for marker in `TrustchainVerifier`.
33pub struct LightClient;
34
35/// Type for representing an endpoint as a base URL and port.
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
37#[serde(rename_all = "camelCase")]
38pub struct Endpoint {
39    pub host: String,
40    pub port: u16,
41}
42
43impl Endpoint {
44    pub fn new(url: String, port: u16) -> Self {
45        Self { host: url, port }
46    }
47    // TODO: add more flexible address handling
48    pub fn to_address(&self) -> String {
49        match self.host.starts_with("http") {
50            true => format!("{}:{}/", self.host, self.port),
51            false => format!("http://{}:{}/", self.host, self.port),
52        }
53    }
54}
55
56/// ION DID resolver.
57pub fn http_resolver(endpoint: &str) -> HTTPSidetreeDIDResolver<ION> {
58    HTTPSidetreeDIDResolver::new(endpoint)
59}
60
61/// Trustchain ION DID resolver for full client.
62pub fn trustchain_resolver(
63    ion_endpoint: &str,
64) -> HTTPTrustchainResolver<HTTPSidetreeDIDResolver<ION>> {
65    HTTPTrustchainResolver::<_, FullClient>::new(http_resolver(ion_endpoint))
66}
67
68/// Trustchain ION DID resolver for light client.
69pub fn trustchain_resolver_light_client(
70    trustchain_endpoint: &str,
71) -> HTTPTrustchainResolver<HTTPSidetreeDIDResolver<ION>, LightClient> {
72    HTTPTrustchainResolver::<_, LightClient>::new(http_resolver(trustchain_endpoint))
73}
74
75/// An error relating for Trustchain-ion crate.
76#[derive(Error, Debug)]
77pub enum TrustchainIONError {
78    /// Key cannot be converted to commmitment value.
79    #[error("Key cannot be converted to commmitment value.")]
80    FailedToConvertToCommitment,
81    /// Commitment value could not be extracted from document metadata.
82    #[error("Commitment value could not be extracted from document metadata.")]
83    FailedToExtractCommitment,
84    /// Incorrect key type provided.
85    #[error("Incorrect key type provided.")]
86    IncorrectKeyType,
87}
88
89/// An error relating to a MongoDB query.
90#[derive(Error, Debug)]
91pub enum TrustchainMongodbError {
92    /// Query returned `None`.
93    #[error("Query returned None.")]
94    QueryReturnedNone,
95    /// Query returned an `Error`.
96    #[error("Query returned Error: {0}")]
97    QueryReturnedError(mongodb::error::Error),
98    /// `Error` creating client.
99    #[error("Error creating client: {0}")]
100    ErrorCreatingClient(mongodb::error::Error),
101}
102
103impl From<mongodb::error::Error> for TrustchainMongodbError {
104    fn from(err: mongodb::error::Error) -> Self {
105        TrustchainMongodbError::QueryReturnedError(err)
106    }
107}
108
109impl From<io::Error> for TrustchainIpfsError {
110    fn from(err: io::Error) -> Self {
111        TrustchainIpfsError::DataDecodingError(err)
112    }
113}
114
115impl From<serde_json::Error> for TrustchainIpfsError {
116    fn from(err: serde_json::Error) -> Self {
117        TrustchainIpfsError::DeserializeError(err)
118    }
119}
120
121/// An error relating to an IPFS query.
122#[derive(Error, Debug)]
123pub enum TrustchainIpfsError {
124    /// Failed to decode IPFS data.
125    #[error("Failed to decode IPFS data.")]
126    DataDecodingError(io::Error),
127    /// Failed to decode IPFS data.
128    #[error("Failed to decode UTF-8 string.")]
129    Utf8DecodingError(FromUtf8Error),
130    /// Failed to decode IPFS data.
131    #[error("Failed to deserialize IPFS content to JSON")]
132    DeserializeError(serde_json::Error),
133}
134
135impl From<bitcoincore_rpc::Error> for TrustchainBitcoinError {
136    fn from(err: bitcoincore_rpc::Error) -> Self {
137        TrustchainBitcoinError::BitcoinCoreRPCError(err)
138    }
139}
140
141impl From<ParseIntError> for TrustchainBitcoinError {
142    fn from(err: ParseIntError) -> Self {
143        TrustchainBitcoinError::BlockHeaderConversionError(err)
144    }
145}
146
147/// An error relating to a Bitcoin RPC API call.
148#[derive(Error, Debug)]
149pub enum TrustchainBitcoinError {
150    /// Failed to convert block header timestamp hex.
151    #[error("Failed to convert block header timestamp hex: {0}")]
152    BlockHeaderConversionError(ParseIntError),
153    /// Failed to decode block header data.
154    #[error("Failed to decode block header data.")]
155    BlockHeaderDecodingError,
156    /// Wrapped bitcoincore_rpc error
157    #[error("Bitcoin core RPC error: {0}")]
158    BitcoinCoreRPCError(bitcoincore_rpc::Error),
159    /// Failed to get block time at height.
160    #[error("Block time was None at height: {0}")]
161    BlockTimeAtHeightError(u64),
162    /// Target date precedes start block timestamp or succeeds end block timestamp.
163    #[error("Target date out of range of block timestamps.")]
164    TargetDateOutOfRange,
165}
166
167// DID
168pub const CONTROLLER_KEY: &str = "controller";
169pub const CREATE_OPERATION_FILENAME_PREFIX: &str = "create_operation_";
170pub const ATTEST_OPERATION_FILENAME_PREFIX: &str = "attest_operation_";
171// TODO: uncomment when update operation functionality merged
172// pub const UPDATE_OPERATION_FILENAME_PREFIX: &str = "update_operation_";
173
174// ION
175pub const ION_METHOD: &str = "ion";
176pub const ION_TEST_METHOD: &str = "ion:test";
177
178// MongoDB
179pub const MONGO_COLLECTION_OPERATIONS: &str = "operations";
180pub const MONGO_FILTER_TYPE: &str = "type";
181pub const MONGO_CREATE_OPERATION: &str = "create";
182pub const MONGO_FILTER_DID_SUFFIX: &str = "didSuffix";
183pub const MONGO_FILTER_TXN_TIME: &str = "txnTime";
184pub const MONGO_FILTER_TXN_NUMBER: &str = "txnNumber";
185pub const MONGO_FILTER_OP_INDEX: &str = "opIndex";
186
187// Bitcoin
188// TODO: consider structs for deserialization similar to trustchain_ion::sidetree module
189pub const TXID_KEY: &str = "txid";
190pub const MERKLE_ROOT_KEY: &str = "merkle_root";
191pub const VERSION_KEY: &str = "version";
192pub const HASH_PREV_BLOCK_KEY: &str = "hash_prev_block";
193pub const TIMESTAMP_KEY: &str = "timestamp";
194pub const BITS_KEY: &str = "bits";
195pub const NONCE_KEY: &str = "nonce";
196
197// Minimum number of zeros for PoW block hash of root
198// TODO: set differently for mainnet and testnet with features
199pub const MIN_POW_ZEROS: usize = 14;
200
201// BIP32
202pub const SIGNING_KEY_DERIVATION_PATH: &str = "m/0h";
203pub const UPDATE_KEY_DERIVATION_PATH: &str = "m/1h";
204pub const RECOVERY_KEY_DERIVATION_PATH: &str = "m/2h";
205
206// IPFS KEY
207pub const SERVICE_TYPE_IPFS_KEY: &str = "IPFSKey";