diff --git a/.github/actions/iota-rebase-sandbox/setup/action.yml b/.github/actions/iota-rebase-sandbox/setup/action.yml index 7e1b9c84eb..0f0554aa89 100644 --- a/.github/actions/iota-rebase-sandbox/setup/action.yml +++ b/.github/actions/iota-rebase-sandbox/setup/action.yml @@ -13,25 +13,29 @@ runs: - name: Set up IOTA Node shell: bash run: | + set -e mkdir -p iota cd iota - # Select platform-specific asset pattern - if [ "${{ inputs.platform }}" = "linux" ]; then - PLATFORM="linux" - else - PLATFORM="macos" - fi + # Set platform + PLATFORM="${{ inputs.platform }}" + echo "Looking for platform: $PLATFORM" - # Get download URL with simpler jq filter + # Get download URL DOWNLOAD_URL=$(curl "https://api.github.com/repos/iotaledger/iota/releases/latest" | \ jq -r --arg p "$PLATFORM" '.assets[] | select(.name | contains($p)) | .browser_download_url') # Download and extract + echo "Downloading from: $DOWNLOAD_URL" curl -L -o iota.tar.gz $DOWNLOAD_URL tar -xzf iota.tar.gz + echo "$PWD" >> $GITHUB_PATH + export PATH="$PWD:$PATH" + + which iota || echo "iota not found in PATH" + ls -la "$PWD" - name: Start the Network shell: bash working-directory: iota - run: ./iota start --with-faucet --force-regenesis & + run: iota start --with-faucet --force-regenesis & diff --git a/.github/actions/rust/sccache/setup-sccache/action.yml b/.github/actions/rust/sccache/setup-sccache/action.yml index 3c29dc661e..b3e5ca1735 100644 --- a/.github/actions/rust/sccache/setup-sccache/action.yml +++ b/.github/actions/rust/sccache/setup-sccache/action.yml @@ -15,8 +15,8 @@ runs: brew update --preinstall brew install sccache - - name: Install sccache (ubuntu-latest) - if: inputs.os == 'ubuntu-latest' + - name: Install sccache (ubuntu-24.04) + if: inputs.os == 'ubuntu-24.04' shell: bash run: | SCCACHE_DOWNLOAD_LINK=https://github.com/mozilla/sccache/releases/download diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index fe2f32225a..5dcf296bff 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -28,7 +28,7 @@ env: jobs: check-for-run-condition: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: should-run: ${{ !github.event.pull_request || github.event.pull_request.draft == false }} steps: @@ -38,7 +38,7 @@ jobs: check-for-modification: needs: check-for-run-condition if: ${{ needs.check-for-run-condition.outputs.should-run == 'true' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: core-modified: ${{ steps.change-detection.outputs.core-modified }} # map step output to job output steps: @@ -67,9 +67,9 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-latest, macos-latest, windows-latest ] + os: [ ubuntu-24.04, macos-latest, windows-latest ] include: - - os: ubuntu-latest + - os: ubuntu-24.04 sccache-path: /home/runner/.cache/sccache - os: macos-latest sccache-path: /Users/runner/Library/Caches/Mozilla.sccache @@ -104,7 +104,7 @@ jobs: os: ${{matrix.os}} - name: Check --no-default-features - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-24.04' run: | cargo metadata --format-version 1 | \ jq -r '.workspace_members[]' | \ @@ -112,7 +112,7 @@ jobs: xargs -I {} cargo check -p {} --no-default-features - name: Check default features - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-24.04' run: | cargo metadata --format-version 1 | \ jq -r '.workspace_members[]' | \ @@ -122,7 +122,7 @@ jobs: # Clean debug target to avoid bloating the GitHub Actions cache. # The previous builds cannot be re-used at all for the full --all-features --release build anyway. - name: Clean target - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-24.04' run: cargo clean # Build the library, tests, and examples without running them to avoid recompilation in the run tests step @@ -133,7 +133,7 @@ jobs: if: matrix.os != 'windows-latest' uses: './.github/actions/iota-rebase-sandbox/setup' with: - platform: ${{ matrix.os == 'ubuntu-latest' && 'linux' || 'macos' }} + platform: ${{ matrix.os == 'ubuntu-24.04' && 'linux' || 'macos' }} - name: Run tests excluding `custom_time` feature if: matrix.os != 'windows-latest' @@ -144,7 +144,7 @@ jobs: - name: Run Rust examples # run examples only on ubuntu for now - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-24.04' run: | cargo metadata --format-version 1 --manifest-path ./examples/Cargo.toml | \ jq -r '.packages[] | select(.name == "examples") | .targets[].name' | \ @@ -154,7 +154,7 @@ jobs: - name: Run Rust Readme examples # run examples only on ubuntu for now - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-24.04' run: | cd bindings/wasm npm ci @@ -176,13 +176,13 @@ jobs: test-wasm: needs: build-wasm if: ${{ needs.check-for-run-condition.outputs.should-run == 'true' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: - os: [ ubuntu-latest ] + os: [ ubuntu-24.04 ] include: - - os: ubuntu-latest + - os: ubuntu-24.04 steps: - uses: actions/checkout@v3 @@ -212,13 +212,13 @@ jobs: test-wasm-firefox: needs: build-wasm if: ${{ needs.check-for-run-condition.outputs.should-run == 'true' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: - os: [ ubuntu-latest ] + os: [ ubuntu-24.04 ] include: - - os: ubuntu-latest + - os: ubuntu-24.04 steps: - uses: actions/checkout@v3 @@ -256,13 +256,13 @@ jobs: test-wasm-chrome: needs: build-wasm if: ${{ needs.check-for-run-condition.outputs.should-run == 'true' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: - os: [ ubuntu-latest ] + os: [ ubuntu-24.04 ] include: - - os: ubuntu-latest + - os: ubuntu-24.04 steps: - uses: actions/checkout@v3 diff --git a/examples/0_basic/5_create_vc.rs b/examples/0_basic/5_create_vc.rs index 3f15effd73..e6ed4610ac 100644 --- a/examples/0_basic/5_create_vc.rs +++ b/examples/0_basic/5_create_vc.rs @@ -36,8 +36,7 @@ async fn main() -> anyhow::Result<()> { // create new issuer account with did document let issuer_storage = get_memstorage()?; let issuer_identity_client = get_client_and_create_account(&issuer_storage).await?; - let (issuer_document, issuer_vm_fragment) = - create_did_document(&issuer_identity_client, &issuer_storage).await?; + let (issuer_document, issuer_vm_fragment) = create_did_document(&issuer_identity_client, &issuer_storage).await?; // create new holder account with did document let holder_storage = get_memstorage()?; diff --git a/examples/0_basic/6_create_vp.rs b/examples/0_basic/6_create_vp.rs index db4d73be3b..916d63e99d 100644 --- a/examples/0_basic/6_create_vp.rs +++ b/examples/0_basic/6_create_vp.rs @@ -54,14 +54,12 @@ async fn main() -> anyhow::Result<()> { // create new issuer account with did document let issuer_storage = get_memstorage()?; let issuer_identity_client = get_client_and_create_account(&issuer_storage).await?; - let (issuer_document, issuer_vm_fragment) = - create_did_document(&issuer_identity_client, &issuer_storage).await?; + let (issuer_document, issuer_vm_fragment) = create_did_document(&issuer_identity_client, &issuer_storage).await?; // create new holder account with did document let holder_storage = get_memstorage()?; let holder_identity_client = get_client_and_create_account(&holder_storage).await?; - let (holder_document, holder_vm_fragment) = - create_did_document(&holder_identity_client, &holder_storage).await?; + let (holder_document, holder_vm_fragment) = create_did_document(&holder_identity_client, &holder_storage).await?; // create new client for verifier // new client actually not necessary, but shows, that client is independent from issuer and holder diff --git a/examples/0_basic/7_revoke_vc.rs b/examples/0_basic/7_revoke_vc.rs index c9d8c31320..c713f70ca9 100644 --- a/examples/0_basic/7_revoke_vc.rs +++ b/examples/0_basic/7_revoke_vc.rs @@ -52,8 +52,7 @@ async fn main() -> anyhow::Result<()> { // create new issuer account with did document let issuer_storage = get_memstorage()?; let issuer_identity_client = get_client_and_create_account(&issuer_storage).await?; - let (mut issuer_document, issuer_vm_fragment) = - create_did_document(&issuer_identity_client, &issuer_storage).await?; + let (mut issuer_document, issuer_vm_fragment) = create_did_document(&issuer_identity_client, &issuer_storage).await?; // create new holder account with did document let holder_storage = get_memstorage()?; diff --git a/examples/1_advanced/4_identity_history.rs b/examples/1_advanced/4_identity_history.rs index f946498386..19f8ae3fdf 100644 --- a/examples/1_advanced/4_identity_history.rs +++ b/examples/1_advanced/4_identity_history.rs @@ -73,8 +73,8 @@ async fn main() -> anyhow::Result<()> { .into_iter() .map(|data| IotaDocument::unpack_from_iota_object_data(&did, &data, true)) .collect::>()?; - println!("Current version: {}", documents[0].to_string()); - println!("Previous version: {}", documents[1].to_string()); + println!("Current version: {}", documents[0]); + println!("Previous version: {}", documents[1]); // Depending on your use case, you can also page through the results // Alternative Step 2 - Page by looping until no result is returned (here with page size 1) diff --git a/examples/1_advanced/7_sd_jwt.rs b/examples/1_advanced/7_sd_jwt.rs index 0e8bbe4465..6ced57c846 100644 --- a/examples/1_advanced/7_sd_jwt.rs +++ b/examples/1_advanced/7_sd_jwt.rs @@ -43,14 +43,12 @@ async fn main() -> anyhow::Result<()> { // Create an identity for the issuer with one verification method `key-1`. let issuer_storage = get_memstorage()?; let issuer_identity_client = get_client_and_create_account(&issuer_storage).await?; - let (issuer_document, issuer_vm_fragment) = - create_did_document(&issuer_identity_client, &issuer_storage).await?; + let (issuer_document, issuer_vm_fragment) = create_did_document(&issuer_identity_client, &issuer_storage).await?; // Create an identity for the holder, in this case also the subject. let holder_storage = get_memstorage()?; let holder_identity_client = get_client_and_create_account(&holder_storage).await?; - let (holder_document, holder_vm_fragment) = - create_did_document(&holder_identity_client, &holder_storage).await?; + let (holder_document, holder_vm_fragment) = create_did_document(&holder_identity_client, &holder_storage).await?; // =========================================================================== // Step 2: Issuer creates and signs a selectively disclosable JWT verifiable credential. diff --git a/examples/1_advanced/8_status_list_2021.rs b/examples/1_advanced/8_status_list_2021.rs index b0137ea486..3a87cb24d2 100644 --- a/examples/1_advanced/8_status_list_2021.rs +++ b/examples/1_advanced/8_status_list_2021.rs @@ -41,8 +41,7 @@ async fn main() -> anyhow::Result<()> { // create new issuer account with did document let issuer_storage = get_memstorage()?; let issuer_identity_client = get_client_and_create_account(&issuer_storage).await?; - let (issuer_document, issuer_vm_fragment) = - create_did_document(&issuer_identity_client, &issuer_storage).await?; + let (issuer_document, issuer_vm_fragment) = create_did_document(&issuer_identity_client, &issuer_storage).await?; // create new holder account with did document let holder_storage = get_memstorage()?; diff --git a/identity_credential/src/credential/jwt_serialization.rs b/identity_credential/src/credential/jwt_serialization.rs index b1d1886183..82bb1ae24c 100644 --- a/identity_credential/src/credential/jwt_serialization.rs +++ b/identity_credential/src/credential/jwt_serialization.rs @@ -32,6 +32,7 @@ use crate::Result; #[serde(transparent)] pub struct JwtCredential(CredentialJwtClaims<'static>); +#[cfg(feature = "validator")] impl TryFrom for Credential { type Error = Error; fn try_from(value: JwtCredential) -> std::result::Result { diff --git a/identity_iota/src/lib.rs b/identity_iota/src/lib.rs index 2550b981d9..12a5d9dc4e 100644 --- a/identity_iota/src/lib.rs +++ b/identity_iota/src/lib.rs @@ -75,8 +75,8 @@ pub mod prelude { pub use identity_iota_core::IotaDID; pub use identity_iota_core::IotaDocument; - #[cfg(feature = "client")] - #[cfg_attr(docsrs, doc(cfg(feature = "client")))] + #[cfg(feature = "resolver")] + #[cfg_attr(docsrs, doc(cfg(feature = "resolver")))] pub use identity_iota_core::DidResolutionHandler; #[cfg(feature = "resolver")] diff --git a/identity_iota_core/Cargo.toml b/identity_iota_core/Cargo.toml index abc09cf2a8..2023c6ad53 100644 --- a/identity_iota_core/Cargo.toml +++ b/identity_iota_core/Cargo.toml @@ -41,7 +41,7 @@ iota-sdk = { git = "https://github.com/iotaledger/iota.git", package = "iota-sdk itertools = { version = "0.13.0", optional = true } move-core-types = { git = "https://github.com/iotaledger/iota.git", package = "move-core-types", rev = "39c83ddcf07894cdee2abd146381d8704205e6e9", optional = true } rand = { version = "0.8.5", optional = true } -secret-storage = { git = "https://github.com/iotaledger/secret-storage.git", branch = "main", optional = true } +secret-storage = { git = "https://github.com/iotaledger/secret-storage.git", tag = "v0.1.0", optional = true } serde-aux = { version = "4.5.0", optional = true } shared-crypto = { git = "https://github.com/iotaledger/iota.git", package = "shared-crypto", rev = "39c83ddcf07894cdee2abd146381d8704205e6e9", optional = true } tokio = { version = "1.29.0", default-features = false, optional = true, features = ["macros", "sync", "rt", "process"] } @@ -51,9 +51,10 @@ iota-crypto = { version = "0.23", default-features = false, features = ["bip39", proptest = { version = "1.0.0", default-features = false, features = ["std"] } # for feature iota-client tests -identity_iota_core= { path = ".", features = ["iota-client"] } # enable for e2e tests +identity_iota_core = { path = ".", features = ["iota-client"] } # enable for e2e tests identity_storage = { path = "../identity_storage", features = ["send-sync-storage", "storage-signer"] } jsonpath-rust = "0.5.1" +lazy_static = "1.5.0" serial_test = "3.1.1" [package.metadata.docs.rs] diff --git a/identity_iota_core/src/document/iota_document.rs b/identity_iota_core/src/document/iota_document.rs index a4cba80fff..f5b682780c 100644 --- a/identity_iota_core/src/document/iota_document.rs +++ b/identity_iota_core/src/document/iota_document.rs @@ -395,7 +395,7 @@ impl IotaDocument { } #[cfg(feature = "iota-client")] -pub mod client_document { +mod client_document { use identity_core::common::Timestamp; use iota_sdk::rpc_types::IotaObjectData; @@ -421,7 +421,7 @@ pub mod client_document { data: &IotaObjectData, allow_empty: bool, ) -> Result { - let unpacked = unpack_identity_data(&did, data).map_err(|_| { + let unpacked = unpack_identity_data(did, data).map_err(|_| { Error::InvalidDoc(identity_document::Error::InvalidDocument( "could not unpack identity data from IotaObjectData", None, @@ -437,7 +437,7 @@ pub mod client_document { } }; let did_doc = - Self::from_iota_document_data(multi_controller.controlled_value(), allow_empty, &did, created, updated)?; + Self::from_iota_document_data(multi_controller.controlled_value(), allow_empty, did, created, updated)?; Ok(did_doc) } @@ -451,7 +451,7 @@ pub mod client_document { /// * document related parsing Errors from `StateMetadataDocument::unpack` /// * possible parsing errors when trying to parse `created` and `updated` to a `Timestamp` pub fn from_iota_document_data( - data: &Vec, + data: &[u8], allow_empty: bool, did: &IotaDID, created: Timestamp, @@ -465,8 +465,7 @@ pub mod client_document { empty_document } else { // we have a value, therefore unpack it - StateMetadataDocument::unpack(data) - .and_then(|state_metadata_doc| state_metadata_doc.into_iota_document(&did))? + StateMetadataDocument::unpack(data).and_then(|state_metadata_doc| state_metadata_doc.into_iota_document(did))? }; // Overwrite `created` and `updated` with given timestamps @@ -732,7 +731,7 @@ mod tests { .parse() .unwrap(); let document = IotaDocument::from_iota_document_data( - &vec![], + &[], true, &did, Timestamp::from_unix(12).unwrap(), @@ -750,7 +749,7 @@ mod tests { // INVALID: reject empty document. assert!(IotaDocument::from_iota_document_data( - &vec![], + &[], false, &did, Timestamp::from_unix(12).unwrap(), diff --git a/identity_iota_core/src/lib.rs b/identity_iota_core/src/lib.rs index 484b44d5a6..e076bbb7e4 100644 --- a/identity_iota_core/src/lib.rs +++ b/identity_iota_core/src/lib.rs @@ -31,5 +31,6 @@ mod document; mod error; mod network; #[cfg(feature = "iota-client")] +/// Contains the rebased Identity and the interaction with the IOTA Client. pub mod rebased; mod state_metadata; diff --git a/identity_iota_core/src/rebased/assets/public_available_vc.rs b/identity_iota_core/src/rebased/assets/public_available_vc.rs index a3812962a8..f2cb5c8c4e 100644 --- a/identity_iota_core/src/rebased/assets/public_available_vc.rs +++ b/identity_iota_core/src/rebased/assets/public_available_vc.rs @@ -60,6 +60,7 @@ impl MoveType for IotaVerifiableCredential { } } +/// A publicly available verifiable credential. #[derive(Debug, Clone)] pub struct PublicAvailableVC { asset: AuthenticatedAsset, @@ -74,16 +75,22 @@ impl Deref for PublicAvailableVC { } impl PublicAvailableVC { + /// Get the ID of the asset. pub fn object_id(&self) -> ObjectID { self.asset.id() } + /// Get the JWT of the credential. pub fn jwt(&self) -> Jwt { String::from_utf8(self.asset.content().data.clone()) .map(Jwt::new) .expect("JWT is valid UTF8") } + /// Create a new publicly available VC. + /// + /// # Returns + /// A new `PublicAvailableVC`. pub async fn new(jwt: Jwt, gas_budget: Option, client: &IdentityClient) -> Result where S: Signer + Sync, @@ -102,6 +109,7 @@ impl PublicAvailableVC { Ok(Self { credential, asset }) } + /// Get a publicly available VC by its ID. pub async fn get_by_id(id: ObjectID, client: &IdentityClientReadOnly) -> Result { let asset = client .get_object_by_id::>(id) diff --git a/identity_iota_core/src/rebased/client/full_client.rs b/identity_iota_core/src/rebased/client/full_client.rs index 066bac68cc..b5014f7c8e 100644 --- a/identity_iota_core/src/rebased/client/full_client.rs +++ b/identity_iota_core/src/rebased/client/full_client.rs @@ -47,8 +47,11 @@ use crate::rebased::Error; use super::get_object_id_from_did; use super::IdentityClientReadOnly; +/// A signature which is used to sign transactions. pub struct IotaKeySignature { + /// The public key of the signature. pub public_key: Vec, + /// The signature of the transaction. pub signature: Vec, } @@ -85,11 +88,16 @@ impl From for String { } } +/// A client for interacting with the IOTA network. #[derive(Clone)] pub struct IdentityClient { + /// [`IdentityClientReadOnly`] instance, used for read-only operations. read_client: IdentityClientReadOnly, + /// The address of the client. address: IotaAddress, + /// The public key of the client. public_key: Vec, + /// The signer of the client. signer: S, } @@ -104,6 +112,7 @@ impl IdentityClient where S: Signer + Sync, { + /// Create a new [`IdentityClient`]. pub async fn new(client: IdentityClientReadOnly, signer: S) -> Result { let public_key = signer .public_key() diff --git a/identity_iota_core/src/rebased/client/read_only.rs b/identity_iota_core/src/rebased/client/read_only.rs index 96cb6e800f..c9ec753403 100644 --- a/identity_iota_core/src/rebased/client/read_only.rs +++ b/identity_iota_core/src/rebased/client/read_only.rs @@ -300,6 +300,11 @@ async fn resolve_unmigrated(client: &IdentityClientReadOnly, object_id: ObjectID Ok(unmigrated_alias.map(Identity::Legacy)) } +/// Extracts the object ID from the given `IotaDID`. +/// +/// # Arguments +/// +/// * `did` - A reference to the `IotaDID` to be converted. pub fn get_object_id_from_did(did: &IotaDID) -> Result { ObjectID::from_str(did.tag_str()) .map_err(|err| Error::DIDResolutionError(format!("could not parse object id from did {did}; {err}"))) diff --git a/identity_iota_core/src/rebased/migration/identity.rs b/identity_iota_core/src/rebased/migration/identity.rs index b1a09d03ac..f617cf1606 100644 --- a/identity_iota_core/src/rebased/migration/identity.rs +++ b/identity_iota_core/src/rebased/migration/identity.rs @@ -57,6 +57,9 @@ const MODULE: &str = "identity"; const NAME: &str = "Identity"; const HISTORY_DEFAULT_PAGE_SIZE: usize = 10; +/// The data stored in an on-chain identity. +pub type IdentityData = (UID, Multicontroller>, Timestamp, Timestamp); + /// An on-chain object holding a DID Document. pub enum Identity { /// A legacy IOTA Stardust's Identity. @@ -230,6 +233,7 @@ impl OnChainIdentity { } } +/// Returns the previous version of the given `history_item`. pub fn has_previous_version(history_item: &IotaObjectData) -> Result { if let Some(Owner::Shared { initial_shared_version }) = history_item.owner { Ok(history_item.version != initial_shared_version) @@ -373,10 +377,7 @@ fn is_identity(value: &IotaParsedMoveObject) -> bool { /// # Errors: /// * in case given data for DID is not an object /// * parsing identity data from object fails -pub(crate) fn unpack_identity_data( - did: &IotaDID, - data: &IotaObjectData, -) -> Result>, Timestamp, Timestamp)>, Error> { +pub(crate) fn unpack_identity_data(did: &IotaDID, data: &IotaObjectData) -> Result, Error> { let content = data .clone() .content diff --git a/identity_iota_core/src/rebased/migration/registry.rs b/identity_iota_core/src/rebased/migration/registry.rs index 41b94a543d..28cc9a1d74 100644 --- a/identity_iota_core/src/rebased/migration/registry.rs +++ b/identity_iota_core/src/rebased/migration/registry.rs @@ -10,12 +10,16 @@ use crate::rebased::client::IdentityClientReadOnly; use super::get_identity; use super::OnChainIdentity; +/// Errors that can occur during migration registry operations. #[derive(thiserror::Error, Debug)] pub enum Error { + /// An error occurred while interacting with the IOTA Client. #[error(transparent)] - ClientError(anyhow::Error), + Client(anyhow::Error), + /// The MigrationRegistry object was not found. #[error("could not locate MigrationRegistry object: {0}")] NotFound(String), + /// The MigrationRegistry object is malformed. #[error("malformed MigrationRegistry's entry: {0}")] Malformed(String), } @@ -36,7 +40,7 @@ pub async fn lookup( .read_api() .get_dynamic_field_object(iota_client.migration_registry_id(), dynamic_field_name) .await - .map_err(|e| Error::ClientError(e.into()))? + .map_err(|e| Error::Client(e.into()))? .data .map(|data| { data @@ -51,9 +55,7 @@ pub async fn lookup( .transpose()?; if let Some(id) = identity_id { - get_identity(iota_client, id) - .await - .map_err(|e| Error::ClientError(e.into())) + get_identity(iota_client, id).await.map_err(|e| Error::Client(e.into())) } else { Ok(None) } diff --git a/identity_iota_core/src/rebased/mod.rs b/identity_iota_core/src/rebased/mod.rs index 334d16e393..7eb41c2a8a 100644 --- a/identity_iota_core/src/rebased/mod.rs +++ b/identity_iota_core/src/rebased/mod.rs @@ -1,13 +1,19 @@ // Copyright 2020-2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +/// Module for handling assets. pub mod assets; +/// Module for handling client operations. pub mod client; mod error; +/// Module for handling migration operations. pub mod migration; +/// Contains the operations of proposals. pub mod proposals; mod sui; +/// Module for handling transactions. pub mod transaction; +/// Contains utility functions. pub mod utils; pub use assets::*; diff --git a/identity_iota_core/src/rebased/proposals/borrow.rs b/identity_iota_core/src/rebased/proposals/borrow.rs index d14292e2b4..341fa0dcc3 100644 --- a/identity_iota_core/src/rebased/proposals/borrow.rs +++ b/identity_iota_core/src/rebased/proposals/borrow.rs @@ -147,6 +147,7 @@ impl ProposalT for Proposal { } } +/// A transaction to execute a borrow proposal. pub struct ExecuteBorrowTx<'i, B> { identity: &'i mut OnChainIdentity, borrow_action: B, diff --git a/identity_iota_core/src/rebased/proposals/config_change.rs b/identity_iota_core/src/rebased/proposals/config_change.rs index 891eef86f8..cec2bc10c5 100644 --- a/identity_iota_core/src/rebased/proposals/config_change.rs +++ b/identity_iota_core/src/rebased/proposals/config_change.rs @@ -91,6 +91,7 @@ impl<'i> ProposalBuilder<'i, ConfigChange> { } impl ConfigChange { + /// Creates a new [`ConfigChange`] proposal action. pub fn new() -> Self { Self::default() } diff --git a/identity_iota_core/src/rebased/proposals/deactivate_did.rs b/identity_iota_core/src/rebased/proposals/deactivate_did.rs index cfca0b9018..71b879f1d4 100644 --- a/identity_iota_core/src/rebased/proposals/deactivate_did.rs +++ b/identity_iota_core/src/rebased/proposals/deactivate_did.rs @@ -28,6 +28,7 @@ use super::ProposalT; pub struct DeactivateDid; impl DeactivateDid { + /// Creates a new [`DeactivateDid`] action. pub const fn new() -> Self { Self } diff --git a/identity_iota_core/src/rebased/proposals/mod.rs b/identity_iota_core/src/rebased/proposals/mod.rs index 766d575b88..ac8c8489f0 100644 --- a/identity_iota_core/src/rebased/proposals/mod.rs +++ b/identity_iota_core/src/rebased/proposals/mod.rs @@ -48,8 +48,10 @@ use crate::rebased::Error; pub trait ProposalT { /// The [`Proposal`] action's type. type Action; + /// The output of the [`Proposal`] type Output; + /// Creates a new [`Proposal`] with the provided action and expiration. async fn create<'i, S>( action: Self::Action, expiration: Option, @@ -59,6 +61,7 @@ pub trait ProposalT { where S: Signer + Sync; + /// Converts the [`Proposal`] into a transaction that can be executed. async fn into_tx<'i, S>( self, identity: &'i mut OnChainIdentity, @@ -67,10 +70,12 @@ pub trait ProposalT { where S: Signer + Sync; + /// Parses the transaction's effects and returns the output of the [`Proposal`]. fn parse_tx_effects(tx_response: &IotaTransactionBlockResponse) -> Result; } impl Proposal { + /// Creates a new [`ApproveProposalTx`] for the provided [`Proposal`] pub fn approve<'i>(&mut self, identity: &'i OnChainIdentity) -> ApproveProposalTx<'_, 'i, A> { ApproveProposalTx { proposal: self, @@ -79,6 +84,7 @@ impl Proposal { } } +/// A builder for creating a [`Proposal`]. #[derive(Debug)] pub struct ProposalBuilder<'i, A> { identity: &'i mut OnChainIdentity, @@ -108,6 +114,7 @@ impl<'i, A> ProposalBuilder<'i, A> { } } + /// Sets the expiration epoch for the [`Proposal`]. pub fn expiration_epoch(mut self, exp: u64) -> Self { self.expiration = Some(exp); self @@ -140,6 +147,7 @@ pub enum ProposalResult { Executed(P::Output), } +/// A transaction to create a [`Proposal`]. #[derive(Debug)] pub struct CreateProposalTx<'i, A> { identity: &'i mut OnChainIdentity, @@ -213,6 +221,7 @@ where } } +/// A transaction to execute a [`Proposal`]. #[derive(Debug)] pub struct ExecuteProposalTx<'i, A> { tx: ProgrammableTransaction, @@ -257,6 +266,7 @@ where } } +/// A transaction to approve a [`Proposal`]. #[derive(Debug)] pub struct ApproveProposalTx<'p, 'i, A> { proposal: &'p mut Proposal, diff --git a/identity_iota_core/src/rebased/proposals/update_did_doc.rs b/identity_iota_core/src/rebased/proposals/update_did_doc.rs index 8d1af3be6b..27ffef54aa 100644 --- a/identity_iota_core/src/rebased/proposals/update_did_doc.rs +++ b/identity_iota_core/src/rebased/proposals/update_did_doc.rs @@ -38,6 +38,7 @@ impl MoveType for UpdateDidDocument { } impl UpdateDidDocument { + /// Creates a new [`UpdateDidDocument`] action. pub fn new(document: IotaDocument) -> Self { Self(document.pack().expect("a valid IotaDocument is packable")) } diff --git a/identity_iota_core/src/rebased/sui/move_calls/identity/borrow_asset.rs b/identity_iota_core/src/rebased/sui/move_calls/identity/borrow_asset.rs index 95837f3ec0..62e1f995af 100644 --- a/identity_iota_core/src/rebased/sui/move_calls/identity/borrow_asset.rs +++ b/identity_iota_core/src/rebased/sui/move_calls/identity/borrow_asset.rs @@ -59,7 +59,7 @@ where let mut ptb = ProgrammableTransactionBuilder::new(); let identity = utils::owned_ref_to_shared_object_arg(identity, &mut ptb, true)?; let controller_cap = ptb.obj(ObjectArg::ImmOrOwnedObject(capability))?; - let (delegation_token, borrow)= utils::get_controller_delegation(&mut ptb, controller_cap, package); + let (delegation_token, borrow) = utils::get_controller_delegation(&mut ptb, controller_cap, package); let proposal_id = ptb.pure(proposal_id)?; // Get the proposal's action as argument. diff --git a/identity_iota_core/src/rebased/sui/move_calls/identity/create.rs b/identity_iota_core/src/rebased/sui/move_calls/identity/create.rs index f36ce0b830..036be6e0b6 100644 --- a/identity_iota_core/src/rebased/sui/move_calls/identity/create.rs +++ b/identity_iota_core/src/rebased/sui/move_calls/identity/create.rs @@ -67,7 +67,7 @@ where vec![ids, vps], ) }; - + let controllers_that_can_delegate = ptb.programmable_move_call( IOTA_FRAMEWORK_PACKAGE_ID, ident_str!("vec_map").into(), @@ -85,7 +85,13 @@ where module: ident_str!("identity").into(), function: ident_str!("new_with_controllers").into(), type_arguments: vec![], - arguments: vec![doc_arg, controllers, controllers_that_can_delegate, threshold_arg, clock], + arguments: vec![ + doc_arg, + controllers, + controllers_that_can_delegate, + threshold_arg, + clock, + ], }))); // Share the resulting identity. diff --git a/identity_iota_core/src/rebased/sui/move_calls/identity/proposal.rs b/identity_iota_core/src/rebased/sui/move_calls/identity/proposal.rs index bb04d73a13..7a56dbde0d 100644 --- a/identity_iota_core/src/rebased/sui/move_calls/identity/proposal.rs +++ b/identity_iota_core/src/rebased/sui/move_calls/identity/proposal.rs @@ -24,7 +24,7 @@ pub(crate) fn approve( let controller_cap = ptb .obj(ObjectArg::ImmOrOwnedObject(controller_cap)) .map_err(|e| Error::InvalidArgument(e.to_string()))?; - let (delegation_token, borrow) = utils::get_controller_delegation(&mut ptb, controller_cap, package); + let (delegation_token, borrow) = utils::get_controller_delegation(&mut ptb, controller_cap, package); let proposal_id = ptb .pure(proposal_id) .map_err(|e| Error::InvalidArgument(e.to_string()))?; diff --git a/identity_iota_core/src/rebased/sui/move_calls/identity/update.rs b/identity_iota_core/src/rebased/sui/move_calls/identity/update.rs index 9ec751425a..34603d54b5 100644 --- a/identity_iota_core/src/rebased/sui/move_calls/identity/update.rs +++ b/identity_iota_core/src/rebased/sui/move_calls/identity/update.rs @@ -20,7 +20,7 @@ pub(crate) fn propose_update( ) -> Result { let mut ptb = ProgrammableTransactionBuilder::new(); let cap_arg = ptb.obj(ObjectArg::ImmOrOwnedObject(capability))?; - let (delegation_token , borrow) = utils::get_controller_delegation(&mut ptb, cap_arg, package_id); + let (delegation_token, borrow) = utils::get_controller_delegation(&mut ptb, cap_arg, package_id); let identity_arg = utils::owned_ref_to_shared_object_arg(identity, &mut ptb, true)?; let exp_arg = utils::option_to_move(expiration, &mut ptb, package_id)?; let doc_arg = ptb.pure(did_doc.as_ref())?; @@ -47,7 +47,7 @@ pub(crate) fn execute_update( ) -> Result { let mut ptb = ProgrammableTransactionBuilder::new(); let cap_arg = ptb.obj(ObjectArg::ImmOrOwnedObject(capability))?; - let (delegation_token, borrow)= utils::get_controller_delegation(&mut ptb, cap_arg, package_id); + let (delegation_token, borrow) = utils::get_controller_delegation(&mut ptb, cap_arg, package_id); let proposal_id = ptb.pure(proposal_id)?; let identity_arg = utils::owned_ref_to_shared_object_arg(identity, &mut ptb, true)?; let clock = utils::get_clock_ref(&mut ptb); diff --git a/identity_iota_core/src/rebased/sui/move_calls/utils.rs b/identity_iota_core/src/rebased/sui/move_calls/utils.rs index bb8b66525e..0a1d380dc3 100644 --- a/identity_iota_core/src/rebased/sui/move_calls/utils.rs +++ b/identity_iota_core/src/rebased/sui/move_calls/utils.rs @@ -27,7 +27,11 @@ pub(crate) fn get_clock_ref(ptb: &mut Ptb) -> Argument { .expect("network has a singleton clock instantiated") } -pub(crate) fn get_controller_delegation(ptb: &mut Ptb, controller_cap: Argument, package: ObjectID) -> (Argument, Argument) { +pub(crate) fn get_controller_delegation( + ptb: &mut Ptb, + controller_cap: Argument, + package: ObjectID, +) -> (Argument, Argument) { let Argument::Result(idx) = ptb.programmable_move_call( package, ident_str!("controller").into(), @@ -53,7 +57,7 @@ pub(crate) fn put_back_delegation_token( ident_str!("controller").into(), ident_str!("put_back").into(), vec![], - vec![controller_cap, delegation_token, borrow] + vec![controller_cap, delegation_token, borrow], ); } diff --git a/identity_iota_core/src/rebased/utils.rs b/identity_iota_core/src/rebased/utils.rs index 57c1dce437..32cf1902b2 100644 --- a/identity_iota_core/src/rebased/utils.rs +++ b/identity_iota_core/src/rebased/utils.rs @@ -15,8 +15,10 @@ use iota_sdk::IotaClientBuilder; use crate::rebased::Error; +/// The local `IOTA` network. pub const LOCAL_NETWORK: &str = "http://127.0.0.1:9000"; +/// Builds an `IOTA` client for the given network. pub async fn get_client(network: &str) -> Result { let client = IotaClientBuilder::default() .build(network) @@ -26,6 +28,7 @@ pub async fn get_client(network: &str) -> Result { Ok(client) } +/// Requests funds from the local `IOTA` faucet. pub async fn request_funds(address: &IotaAddress) -> anyhow::Result<()> { let output = Command::new("iota") .arg("client") @@ -49,9 +52,12 @@ pub async fn request_funds(address: &IotaAddress) -> anyhow::Result<()> { Ok(()) } +/// Trait for types that can be converted to a Move type. pub trait MoveType: Serialize { + /// Returns the Move type for this type. fn move_type(package: ObjectID) -> TypeTag; + /// Tries to convert this type to a Move argument. fn try_to_argument( &self, ptb: &mut ProgrammableTransactionBuilder, diff --git a/identity_iota_core/tests/e2e/common.rs b/identity_iota_core/tests/e2e/common.rs index de724abac0..1a4fad9846 100644 --- a/identity_iota_core/tests/e2e/common.rs +++ b/identity_iota_core/tests/e2e/common.rs @@ -2,11 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 #![allow(dead_code)] -use std::io::Write; -use std::ops::Deref; -use std::sync::Arc; -use std::sync::LazyLock; - use anyhow::anyhow; use anyhow::Context; use identity_iota_core::rebased::client::IdentityClient; @@ -36,10 +31,14 @@ use iota_sdk::types::IOTA_FRAMEWORK_PACKAGE_ID; use iota_sdk::IotaClient; use iota_sdk::IotaClientBuilder; use jsonpath_rust::JsonPathQuery; +use lazy_static::lazy_static; use move_core_types::ident_str; use move_core_types::language_storage::StructTag; use secret_storage::Signer; use serde_json::Value; +use std::io::Write; +use std::ops::Deref; +use std::sync::Arc; use tokio::process::Command; use tokio::sync::OnceCell; @@ -69,7 +68,10 @@ pub const TEST_DOC: &[u8] = &[ 50, 50, 84, 49, 50, 58, 49, 52, 58, 51, 50, 90, 34, 44, 34, 117, 112, 100, 97, 116, 101, 100, 34, 58, 34, 50, 48, 50, 52, 45, 48, 53, 45, 50, 50, 84, 49, 50, 58, 49, 52, 58, 51, 50, 90, 34, 125, 125, ]; -pub static TEST_COIN_TYPE: LazyLock = LazyLock::new(|| "0x2::coin::Coin".parse().unwrap()); + +lazy_static! { + pub static ref TEST_COIN_TYPE: StructTag = "0x2::coin::Coin".parse().unwrap(); +} pub async fn get_client() -> anyhow::Result { let client = IotaClientBuilder::default().build_localnet().await?; diff --git a/identity_iota_core/tests/e2e/identity.rs b/identity_iota_core/tests/e2e/identity.rs index 7dde485e13..6317f06515 100644 --- a/identity_iota_core/tests/e2e/identity.rs +++ b/identity_iota_core/tests/e2e/identity.rs @@ -204,7 +204,6 @@ async fn can_get_historical_identity_data() -> anyhow::Result<()> { }; let history = updated_identity.get_history(&identity_client, None, None).await?; - let versions: Vec = history.iter().map(|elem| elem.version).collect(); // test check for previous version let has_previous_version_responses: Vec = history diff --git a/identity_resolver/src/resolution/resolver.rs b/identity_resolver/src/resolution/resolver.rs index cd19343e45..50ca40b2e7 100644 --- a/identity_resolver/src/resolution/resolver.rs +++ b/identity_resolver/src/resolution/resolver.rs @@ -20,7 +20,7 @@ use super::commands::Command; use super::commands::SendSyncCommand; use super::commands::SingleThreadedCommand; -/// Convenience type for resolving DID documents from different DID methods. +/// Convenience type for resolving DID documents from different DID methods. /// /// # Configuration /// @@ -394,7 +394,9 @@ mod tests { if self.0.id().as_str() == did.as_str() { Ok(self.0.clone()) } else { - Err(identity_iota_core::Error::DIDResolutionError("DID not found".to_string())) + Err(identity_iota_core::Error::DIDResolutionError( + "DID not found".to_string(), + )) } } }