Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Root event date #125

Merged
merged 23 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fa801d4
Add function to convert a block height to unix timestamp
thobson88 Sep 15, 2023
be9b628
Implement date-to-block-height-range function
thobson88 Sep 16, 2023
a99ff5a
Remove client argument from query_mongodb function
thobson88 Sep 17, 2023
dfc3242
Fix unit tests; add new mongo DB query function
thobson88 Sep 18, 2023
0550963
Implement function to query MongoDB over a block height interval
thobson88 Sep 18, 2023
18ee41b
Add root module; refactor utils functions
thobson88 Sep 22, 2023
0e46a98
Add opIndex=0 condition for root DID candidates
thobson88 Sep 24, 2023
ccb433f
Add HTTP endpoint for getting root DID candidates
thobson88 Sep 24, 2023
61a3d2d
Add RootCandidatesResult type; add assertions in unit test
thobson88 Sep 25, 2023
f48b4c7
Remove obsolete comment
thobson88 Sep 25, 2023
23c66ca
Add cache of root DID candidates in AppState
thobson88 Sep 25, 2023
bc931a3
Add date field in RootCandidatesResult struct
thobson88 Sep 26, 2023
1fb6333
Rename txid field in RootCandidate struct
thobson88 Sep 28, 2023
fad5cbc
Add HTTP endpoint to get block timestamp
thobson88 Sep 28, 2023
77b5dbc
Add block height field in RootCandidate struct
thobson88 Sep 28, 2023
9997e0b
Merge branch 'main' into root-event-date
thobson88 Oct 11, 2023
6326fec
Fix build errors
thobson88 Oct 11, 2023
cb106e5
Clippy fixes
thobson88 Oct 13, 2023
22a03a8
Use RwLock for root candidates instead of Mutex
thobson88 Oct 13, 2023
717c9b5
Delete obsolete comment
thobson88 Oct 13, 2023
92fafb0
Clippy fixes
thobson88 Oct 13, 2023
e5bc179
Remove obsolete comments
thobson88 Oct 13, 2023
07ab3c3
Improve HTTP status codes on root error
thobson88 Oct 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions trustchain-api/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,9 @@ mod tests {
use trustchain_ion::verifier::IONVerifier;

// The root event time of DID documents in `trustchain-ion/src/data.rs` used for unit tests and the test below.
const ROOT_EVENT_TIME_1: u32 = 1666265405;
const ROOT_EVENT_TIME_1: u64 = 1666265405;

const TEST_UNSIGNED_VC: &str = r##"{
const TEST_UNSIGNED_VC: &str = r#"{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1",
Expand All @@ -283,7 +283,7 @@ mod tests {
}
}
}
"##;
"#;

#[ignore = "requires a running Sidetree node listening on http://localhost:3000"]
#[tokio::test]
Expand Down
7 changes: 4 additions & 3 deletions trustchain-cli/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Some(time) => time.parse::<u32>().unwrap(),
None => cli_config().root_event_time,
};
let did_chain = TrustchainAPI::verify(did, root_event_time, &verifier).await?;
let did_chain =
TrustchainAPI::verify(did, root_event_time.into(), &verifier).await?;
println!("{did_chain}");
}
_ => panic!("Unrecognised DID subcommand."),
Expand Down Expand Up @@ -186,8 +187,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Some(("verify", sub_matches)) => {
let verbose = sub_matches.get_one::<u8>("verbose");
let root_event_time = match sub_matches.get_one::<String>("root_event_time") {
Some(time) => time.parse::<u32>().unwrap(),
None => cli_config().root_event_time,
Some(time) => time.parse::<u64>().unwrap(),
None => cli_config().root_event_time.into(),
};
// Deserialize
let credential: Credential =
Expand Down
4 changes: 2 additions & 2 deletions trustchain-cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ mod tests {

#[test]
fn test_deserialize() {
let config_string = r##"
let config_string = r#"
[cli]
root_event_time = 1666971942
ion_endpoint.host = "http://127.0.0.1"
ion_endpoint.port = 3000

[non_core]
key = "value"
"##;
"#;

let config: CLIConfig = parse_toml(config_string);

Expand Down
4 changes: 2 additions & 2 deletions trustchain-core/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ mod tests {
TEST_TRUSTCHAIN_DOCUMENT_METADATA,
};

const ROOT_SIGNING_KEYS: &str = r##"
const ROOT_SIGNING_KEYS: &str = r#"
[
{
"kty": "EC",
Expand All @@ -318,7 +318,7 @@ mod tests {
"y": "kWvmS7ZOvDUhF8syO08PBzEpEk3BZMuukkvEJOKSjqE"
}
]
"##;
"#;

#[test]
fn test_get_proof() -> Result<(), Box<dyn std::error::Error>> {
Expand Down
52 changes: 26 additions & 26 deletions trustchain-core/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ pub const TEST_SIDETREE_DOCUMENT_MULTIPLE_KEYS: &str = r##"
// Previous versions that don't match example keys, to remove:
// "recoveryCommitment" : "EiBKWQyomumgZvqiRVZnqwA2-7RVZ6Xr-cwDRmeXJT_k9g",
// "updateCommitment" : "EiCe3q-ZByJnzI6CwGIDj-M67W-Yv78L3ejxcuEDxnWzMg"
pub const TEST_SIDETREE_DOCUMENT_METADATA: &str = r##"
pub const TEST_SIDETREE_DOCUMENT_METADATA: &str = r#"
{
"canonicalId" : "did:ion:test:EiCBr7qGDecjkR2yUBhn3aNJPUR3TSEOlkpNcL0Q5Au9ZQ",
"method" : {
Expand All @@ -283,12 +283,12 @@ pub const TEST_SIDETREE_DOCUMENT_METADATA: &str = r##"
"updateCommitment" : "EiBWPR1JNdAQ4j3ZMqurb4rt10NA7s17lztFF9OIcEO3ew"
}
}
"##;
"#;

// Previous versions that don't match example keys, to remove:
// "recoveryCommitment" : "EiBKWQyomumgZvqiRVZnqwA2-7RVZ6Xr-cwDRmeXJT_k9g",
// "updateCommitment" : "EiCe3q-ZByJnzI6CwGIDj-M67W-Yv78L3ejxcuEDxnWzMg"
pub const TEST_TRUSTCHAIN_DOCUMENT_METADATA: &str = r##"
pub const TEST_TRUSTCHAIN_DOCUMENT_METADATA: &str = r#"
{
"canonicalId" : "did:ion:test:EiCBr7qGDecjkR2yUBhn3aNJPUR3TSEOlkpNcL0Q5Au9ZQ",
"method" : {
Expand All @@ -302,7 +302,7 @@ pub const TEST_TRUSTCHAIN_DOCUMENT_METADATA: &str = r##"
"proofValue" : "eyJhbGciOiJFUzI1NksifQ.IkVpQmNiTkRRcjZZNHNzZGc5QXo4eC1qNy1yS1FuNWk5T2Q2S3BjZ2c0RU1KOXci.Nii8p38DtzyurmPHO9sV2JLSH7-Pv-dCKQ0Y-H34rplwhhwca2nSra4ZofcUsHCG6u1oKJ0x4AmMUD2_3UIhRA"
}
}
"##;
"#;

pub const TEST_SIDETREE_DOCUMENT_WITH_CONTROLLER: &str = r##"
{
Expand Down Expand Up @@ -396,7 +396,7 @@ pub const TEST_TRUSTCHAIN_DOCUMENT: &str = r##"
}
"##;

pub const TEST_SIGNING_KEYS: &str = r##"[
pub const TEST_SIGNING_KEYS: &str = r#"[
{
"kty": "EC",
"crv": "secp256k1",
Expand All @@ -412,49 +412,49 @@ pub const TEST_SIGNING_KEYS: &str = r##"[
"d": "U7pUq3BovVnYT1mi1lds60wbueUKb5GobV_WvjOuY14"
}
]
"##;
"#;

pub const TEST_UPDATE_KEY: &str = r##"{
pub const TEST_UPDATE_KEY: &str = r#"{
"kty": "EC",
"crv": "secp256k1",
"x": "2hm19BwmXmR8Vfuw2XbGrusm89Pg6dyExlzDfc-CiM8",
"y": "uFjW0fKdhHaY4c_5E9Wkk3cPi9sJ5rP3oyl1ssV_X6A",
"d": "Z2vJqNRjbWvJX2NzABKlHI2V00HWmV2KNI5P4mmxRbg"
}"##;
}"#;

pub const TEST_NEXT_UPDATE_KEY: &str = r##"{
pub const TEST_NEXT_UPDATE_KEY: &str = r#"{
"kty": "EC",
"crv": "secp256k1",
"x": "hm_Pj46yibXbFNyARPXfOKIAEI_UKqfmZwzZDfbUSSk",
"y": "Djxgs6Ex71m6K0QCrn4l2naNo4F6IYXfu0LrBhW2RQU",
"d": "rAUu7DWaQ2ceSap_NzJNj1YOD2yP_bf1JqabuQJz6rc"
}"##;
}"#;

pub const TEST_RECOVERY_KEY: &str = r##"{
pub const TEST_RECOVERY_KEY: &str = r#"{
"kty": "EC",
"crv": "secp256k1",
"x": "_Z1JRmGwvj0jIpDW-QF0dmQnAL8D_FuNg2WxF7uJSYo",
"y": "orKbmG6L6kRugAB2OWzWNgulXRfyOR06GTm353Er--c",
"d": "YobJpI7p7T5dfU0cDRE4SQwp0eOFR6LOGrsqZE1GG1A"
}"##;
}"#;

pub const TEST_ROOT_SIGNING_PK: &str = r##"
pub const TEST_ROOT_SIGNING_PK: &str = r#"
{
"kty": "EC",
"crv": "secp256k1",
"x": "7ReQHHysGxbyuKEQmspQOjL7oQUqDTldTHuc9V3-yso",
"y": "kWvmS7ZOvDUhF8syO08PBzEpEk3BZMuukkvEJOKSjqE"
}
"##;
"#;

pub const TEST_ROOT_PLUS_1_SIGNING_KEY: &str = r##"
pub const TEST_ROOT_PLUS_1_SIGNING_KEY: &str = r#"
{
"kty": "EC",
"crv": "secp256k1",
"x": "aApKobPO8H8wOv-oGT8K3Na-8l-B1AE3uBZrWGT6FJU",
"y": "dspEqltAtlTKJ7cVRP_gMMknyDPqUw-JHlpwS2mFuh0"
}
"##;
"#;

pub const TEST_ROOT_DOCUMENT: &str = r##"
{
Expand Down Expand Up @@ -599,7 +599,7 @@ pub const TEST_ROOT_PLUS_2_DOCUMENT: &str = r##"
}
"##;

pub const TEST_ROOT_DOCUMENT_METADATA: &str = r##"
pub const TEST_ROOT_DOCUMENT_METADATA: &str = r#"
{
"canonicalId": "did:ion:test:EiCClfEdkTv_aM3UnBBhlOV89LlGhpQAbfeZLFdFxVFkEg",
"method": {
Expand All @@ -608,9 +608,9 @@ pub const TEST_ROOT_DOCUMENT_METADATA: &str = r##"
"recoveryCommitment": "EiCymv17OGBAs7eLmm4BIXDCQBVhdOUAX5QdpIrN4SDE5w"
}
}
"##;
"#;

pub const TEST_ROOT_PLUS_1_DOCUMENT_METADATA: &str = r##"
pub const TEST_ROOT_PLUS_1_DOCUMENT_METADATA: &str = r#"
{
"proof": {
"type": "JsonWebSignature2020",
Expand All @@ -624,22 +624,22 @@ pub const TEST_ROOT_PLUS_1_DOCUMENT_METADATA: &str = r##"
"updateCommitment": "EiA0-GpdeoAa4v0-K4YCHoNTjAPsoroDy7pleDIc4a3_QQ"
}
}
"##;
"#;

/// Root JWK public key
pub const TEST_ROOT_JWK_PK: &str = r##"
pub const TEST_ROOT_JWK_PK: &str = r#"
{
"kty": "EC",
"crv": "secp256k1",
"x": "7ReQHHysGxbyuKEQmspQOjL7oQUqDTldTHuc9V3-yso",
"y": "kWvmS7ZOvDUhF8syO08PBzEpEk3BZMuukkvEJOKSjqE"
}
"##;
"#;

/// Proof value from metadata
pub const TEST_ROOT_PLUS_1_JWT: &str = "eyJhbGciOiJFUzI1NksifQ.IkVpQXM5dkx2SmdaNkFHMk5XbUFmTnBrbl9EMlNSSUFSa2tCWE9kajZpMk84Umci.awNd-_O1N1ycZ6i_BxeLGV14ok51Ii2x9f1FBBCflyAWw773sqiHvQRGHIMBebKMnzbxVybFu2qUEPWUuRAC9g";

pub const TEST_ROOT_PLUS_2_DOCUMENT_METADATA: &str = r##"
pub const TEST_ROOT_PLUS_2_DOCUMENT_METADATA: &str = r#"
{
"canonicalId": "did:ion:test:EiAtHHKFJWAk5AsM3tgCut3OiBY4ekHTf66AAjoysXL65Q",
"method": {
Expand All @@ -653,7 +653,7 @@ pub const TEST_ROOT_PLUS_2_DOCUMENT_METADATA: &str = r##"
"type": "JsonWebSignature2020"
}
}
"##;
"#;
/// Proof value from metadata
pub const TEST_ROOT_PLUS_2_JWT: &str = "eyJhbGciOiJFUzI1NksifQ.IkVpQTNtT25QRklDbTdyc2ljVjRIaFMtNjhrT21xMndqa2tlMEtkRnkzQWlWZlEi.Fxlbm8osH2O5KOQ9sS21bypT_WoWxVD8toCU4baBnLk_gOxiOy_n3cMFMVANJ8usPrKAfRFeC27ATTkWBYZzuw";

Expand Down Expand Up @@ -1032,7 +1032,7 @@ pub const TEST_DID_CHAIN_REVERSED: &str = r##"
"##;

/// Test credential: no issuer is present for the unit test
pub const TEST_CREDENTIAL: &str = r##"{
pub const TEST_CREDENTIAL: &str = r#"{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1",
Expand All @@ -1054,4 +1054,4 @@ pub const TEST_CREDENTIAL: &str = r##"{
}
}
}
"##;
"#;
28 changes: 26 additions & 2 deletions trustchain-core/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use ssi::did::{Document, ServiceEndpoint, VerificationMethod, VerificationMethod
use ssi::jwk::JWK;
use ssi::one_or_many::OneOrMany;
use std::path::{Path, PathBuf};

use std::sync::Once;

/// Gets the type of an object as a String. For diagnostic purposes (debugging) only.
Expand Down Expand Up @@ -99,6 +100,11 @@ pub fn get_did_suffix(did: &str) -> &str {
did.split(':').last().unwrap()
}

/// Converts a short-form DID into a complete DID.
pub fn get_did_from_suffix(did_suffix: &str, method_and_network: &str) -> String {
format!("did:{method_and_network}:{did_suffix}")
}

/// [`JSON_CANONICALIZATION_SCHEME`](https://identity.foundation/sidetree/spec/v1.0.0/#json-canonicalization-scheme)
pub fn canonicalize<T: Serialize + ?Sized>(value: &T) -> Result<String, serde_json::Error> {
serde_jcs::to_string(value)
Expand Down Expand Up @@ -302,6 +308,24 @@ mod tests {
};
use ssi::did::Document;

#[test]
fn test_get_did_from_suffix() {
let did_suffix = "EiCClfEdkTv_aM3UnBBhlOV89LlGhpQAbfeZLFdFxVFkEg";
let mut method_and_network = "ion";
let result = get_did_from_suffix(did_suffix, method_and_network);
assert_eq!(
result,
"did:ion:EiCClfEdkTv_aM3UnBBhlOV89LlGhpQAbfeZLFdFxVFkEg"
);

method_and_network = "ion:test";
let result = get_did_from_suffix(did_suffix, method_and_network);
assert_eq!(
result,
"did:ion:test:EiCClfEdkTv_aM3UnBBhlOV89LlGhpQAbfeZLFdFxVFkEg"
);
}

#[test]
fn test_generate_key() {
let result = generate_key();
Expand Down Expand Up @@ -456,12 +480,12 @@ mod tests {
assert!(!json_contains(&candidate, &expected));

// Entire expected object nested:
let exp_str = r##"{"publicKeyJwk" : {
let exp_str = r#"{"publicKeyJwk" : {
"crv": "secp256k1",
"kty": "EC",
"x": "7ReQHHysGxbyuKEQmspQOjL7oQUqDTldTHuc9V3-yso",
"y": "kWvmS7ZOvDUhF8syO08PBzEpEk3BZMuukkvEJOKSjqE"
}}"##;
}}"#;

let expected: serde_json::Value = serde_json::from_str(exp_str).unwrap();
assert!(json_contains(&candidate, &expected));
Expand Down
2 changes: 1 addition & 1 deletion trustchain-core/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ impl From<serde_json::Error> for VerifierError {
}

/// A Unix timestamp.
pub type Timestamp = u32;
pub type Timestamp = u64;

/// A verifiably-timestamped DID.
pub trait VerifiableTimestamp {
Expand Down
4 changes: 2 additions & 2 deletions trustchain-ffi/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use ssi::vc::LinkedDataProofOptions;
use std::{fs, str::FromStr};
use trustchain_core::TRUSTCHAIN_CONFIG;
use trustchain_core::{verifier::Timestamp, TRUSTCHAIN_CONFIG};
use trustchain_ion::{Endpoint, URL};

use crate::mobile::FFIMobileError;
Expand Down Expand Up @@ -65,7 +65,7 @@ impl Default for EndpointOptions {
#[serde(rename_all = "camelCase")]
pub struct TrustchainOptions {
pub signature_only: bool,
pub root_event_time: u32,
pub root_event_time: Timestamp,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
Expand Down
22 changes: 22 additions & 0 deletions trustchain-http/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use trustchain_core::{
commitment::CommitmentError, issuer::IssuerError, resolver::ResolverError, vc::CredentialError,
verifier::VerifierError, vp::PresentationError,
};
use trustchain_ion::root::TrustchainRootError;

// TODO: refine and add doc comments for error variants
#[derive(Error, Debug)]
Expand All @@ -20,6 +21,8 @@ pub enum TrustchainHTTPError {
ResolverError(ResolverError),
#[error("Trustchain issuer error: {0}")]
IssuerError(IssuerError),
#[error("Trustchain root error: {0}")]
RootError(TrustchainRootError),
#[error("Trustchain presentation error: {0}")]
PresentationError(PresentationError),
#[error("Credential does not exist.")]
Expand Down Expand Up @@ -55,12 +58,19 @@ impl From<VerifierError> for TrustchainHTTPError {
TrustchainHTTPError::VerifierError(err)
}
}

impl From<IssuerError> for TrustchainHTTPError {
fn from(err: IssuerError) -> Self {
TrustchainHTTPError::IssuerError(err)
}
}

impl From<TrustchainRootError> for TrustchainHTTPError {
fn from(err: TrustchainRootError) -> Self {
TrustchainHTTPError::RootError(err)
}
}

impl From<PresentationError> for TrustchainHTTPError {
fn from(err: PresentationError) -> Self {
TrustchainHTTPError::PresentationError(err)
Expand Down Expand Up @@ -108,6 +118,18 @@ impl IntoResponse for TrustchainHTTPError {
err @ TrustchainHTTPError::NoCredentialIssuer => {
(StatusCode::BAD_REQUEST, err.to_string())
}
ref err @ TrustchainHTTPError::RootError(ref variant) => match variant {
TrustchainRootError::NoUniqueRootEvent(_) => {
(StatusCode::BAD_REQUEST, err.to_string())
}
TrustchainRootError::InvalidDate(_, _, _) => {
(StatusCode::BAD_REQUEST, err.to_string())
}
TrustchainRootError::FailedToParseBlockHeight(_) => {
(StatusCode::BAD_REQUEST, err.to_string())
}
_ => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()),
},
err @ TrustchainHTTPError::FailedToVerifyCredential => {
(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
}
Expand Down
Loading
Loading