Skip to content
Snippets Groups Projects
Select Git revision
  • fe571d884ebaab8b12a1bf299de45c7efc633c98
  • master default protected
  • fix_picked_up_file_in_runtime_release
  • network/gtest-1000 protected
  • upgradable-multisig
  • runtime/gtest-1000
  • network/gdev-800 protected
  • cgeek/issue-297-cpu
  • gdev-800-tests
  • update-docker-compose-rpc-squid-names
  • fix-252
  • 1000i100-test
  • hugo/tmp-0.9.1
  • network/gdev-803 protected
  • hugo/endpoint-gossip
  • network/gdev-802 protected
  • hugo/distance-precompute
  • network/gdev-900 protected
  • tuxmain/anonymous-tx
  • debug/podman
  • hugo/195-doc
  • gtest-1000-0.11.1 protected
  • gtest-1000-0.11.0 protected
  • gtest-1000 protected
  • gdev-900-0.10.1 protected
  • gdev-900-0.10.0 protected
  • gdev-900-0.9.2 protected
  • gdev-800-0.8.0 protected
  • gdev-900-0.9.1 protected
  • gdev-900-0.9.0 protected
  • gdev-803 protected
  • gdev-802 protected
  • runtime-801 protected
  • gdev-800 protected
  • runtime-800-bis protected
  • runtime-800 protected
  • runtime-800-backup protected
  • runtime-701 protected
  • runtime-700 protected
  • runtime-600 protected
  • runtime-500 protected
41 results

release_runtime.rs

Blame
  • identities.rs 12.05 KiB
    //  Copyright (C) 2017-2019  The AXIOM TEAM Association.
    //
    // This program is free software: you can redistribute it and/or modify
    // it under the terms of the GNU Affero General Public License as
    // published by the Free Software Foundation, either version 3 of the
    // License, or (at your option) any later version.
    //
    // This program is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU Affero General Public License for more details.
    //
    // You should have received a copy of the GNU Affero General Public License
    // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    
    //! Identities stored index.
    
    use crate::constants::*;
    use crate::paging::PagingFilter;
    use crate::*;
    use dubp_common_doc::traits::Document;
    use dubp_common_doc::{BlockNumber, Blockstamp};
    use dubp_user_docs::documents::identity::IdentityDocumentV10;
    use dup_crypto::keys::*;
    use durs_dbs_tools::DbError;
    use durs_wot::WotId;
    use serde::{Deserialize, Serialize};
    use std::collections::HashMap;
    
    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
    /// Identities filter
    pub struct IdentitiesFilter {
        /// Pagination parameters
        pub paging: PagingFilter,
        /// Filter identities by public key
        pub by_pubkey: Option<PubKey>,
    }
    
    impl Default for IdentitiesFilter {
        fn default() -> Self {
            IdentitiesFilter {
                paging: PagingFilter::default(),
                by_pubkey: None,
            }
        }
    }
    
    impl IdentitiesFilter {
        /// Create "by pubkey" filter
        pub fn by_pubkey(pubkey: PubKey) -> Self {
            IdentitiesFilter {
                paging: PagingFilter::default(),
                by_pubkey: Some(pubkey),
            }
        }
    }
    
    #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)]
    /// Identity state
    pub enum DbIdentityState {
        /// Member
        Member(Vec<usize>),
        /// Expire Member
        ExpireMember(Vec<usize>),
        /// Explicit Revoked
        ExplicitRevoked(Vec<usize>),
        /// Explicit Revoked after expire
        ExplicitExpireRevoked(Vec<usize>),
        /// Implicit revoked
        ImplicitRevoked(Vec<usize>),
    }
    
    #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)]
    /// Identity in database
    pub struct DbIdentity {
        /// Identity hash
        pub hash: String,
        /// Identity state
        pub state: DbIdentityState,
        /// Blockstamp the identity was written
        pub joined_on: Blockstamp,
        /// Blockstamp the identity was expired
        pub expired_on: Option<Blockstamp>,
        /// Blockstamp the identity was revoked
        pub revoked_on: Option<Blockstamp>,
        /// Identity document
        pub idty_doc: IdentityDocumentV10,
        /// Identity wot id
        pub wot_id: WotId,
        /// Membership created block number
        pub ms_created_block_id: BlockNumber,
        /// Timestamp from which membership can be renewed
        pub ms_chainable_on: Vec<u64>,
        /// Timestamp from which the identity can write a new certification
        pub cert_chainable_on: Vec<u64>,
    }
    
    /// Get identities in databases
    pub fn get_identities<DB: DbReadable>(
        db: &DB,
        filters: IdentitiesFilter,
        current_block_id: BlockNumber,
    ) -> Result<Vec<DbIdentity>, DbError> {
        if let Some(pubkey) = filters.by_pubkey {
            if let Some(idty) = get_identity_by_pubkey(db, &pubkey)? {
                Ok(vec![idty])
            } else {
                Ok(vec![])
            }
        } else {
            let mut identities: Vec<DbIdentity> = Vec::new();
            db.read(|r| {
                let greatest_wot_id = crate::current_meta_datas::get_greatest_wot_id_(db, r)?;
                for wot_id in 0..=greatest_wot_id.0 {
                    if let Some(db_idty) = get_identity_by_wot_id_(db, r, WotId(wot_id))? {
                        if filters
                            .paging
                            .check_created_on(db_idty.idty_doc.blockstamp().id, current_block_id)
                        {
                            identities.push(db_idty);
                        }
                    }
                }
                Ok(())
            })?;
            identities.sort_by(|i1, i2| {
                i1.idty_doc
                    .blockstamp()
                    .id
                    .cmp(&i2.idty_doc.blockstamp().id)
            });
            Ok(identities
                .into_iter()
                .skip(filters.paging.page_size * filters.paging.page_number)
                .take(filters.paging.page_size)
                .collect())
        }
    }
    
    /// Get identity by pubkey in databases
    pub fn get_identity_by_pubkey<DB: DbReadable>(
        db: &DB,
        pubkey: &PubKey,
    ) -> Result<Option<DbIdentity>, DbError> {
        db.read(|r| get_identity_by_pubkey_(db, r, pubkey))
    }
    
    /// Get identity by pubkey
    pub fn get_identity_by_pubkey_<DB: DbReadable, R: DbReader>(
        db: &DB,
        r: &R,
        pubkey: &PubKey,
    ) -> Result<Option<DbIdentity>, DbError> {
        if let Some(wot_id) = get_wot_id_(db, r, pubkey)? {
            get_identity_by_wot_id_(db, r, wot_id)
        } else {
            Ok(None)
        }
    }
    
    /// Get identity by pubkey
    #[inline]
    pub fn get_identity_by_wot_id<DB: DbReadable>(
        db: &DB,
        wot_id: WotId,
    ) -> Result<Option<DbIdentity>, DbError> {
        db.read(|r| get_identity_by_wot_id_(db, r, wot_id))
    }
    
    /// Get identity by pubkey
    #[inline]
    pub fn get_identity_by_wot_id_<DB: DbReadable, R: DbReader>(
        db: &DB,
        r: &R,
        wot_id: WotId,
    ) -> Result<Option<DbIdentity>, DbError> {
        if let Some(v) = db.get_int_store(IDENTITIES).get(r, wot_id.0 as u32)? {
            Ok(Some(DB::from_db_value(v)?))
        } else {
            Ok(None)
        }
    }
    
    /// Get uid from pubkey
    #[inline]
    pub fn get_uid<DB: DbReadable>(db: &DB, pubkey: &PubKey) -> Result<Option<String>, DbError> {
        Ok(get_identity_by_pubkey(db, pubkey)?.map(|db_idty| db_idty.idty_doc.username().to_owned()))
    }
    
    /// Get uid from pubkey
    #[inline]
    pub fn get_uid_<DB: DbReadable, R: DbReader>(
        db: &DB,
        r: &R,
        pubkey: &PubKey,
    ) -> Result<Option<String>, DbError> {
        Ok(get_identity_by_pubkey_(db, r, pubkey)?
            .map(|db_idty| db_idty.idty_doc.username().to_owned()))
    }
    
    /// Get wot id from uid
    pub fn get_wot_id_from_uid<DB: DbReadable>(db: &DB, uid: &str) -> Result<Option<WotId>, DbError> {
        db.read(|r| {
            let greatest_wot_id = crate::current_meta_datas::get_greatest_wot_id_(db, r)?;
            for wot_id in 0..=greatest_wot_id.0 {
                if let Some(db_idty) = get_identity_by_wot_id_(db, r, WotId(wot_id))? {
                    if db_idty.idty_doc.username() == uid {
                        return Ok(Some(WotId(wot_id)));
                    }
                }
            }
            Ok(None)
        })
    }
    
    /// Get identity wot_id
    pub fn get_wot_id<DB: DbReadable>(db: &DB, pubkey: &PubKey) -> Result<Option<WotId>, DbError> {
        db.read(|r| get_wot_id_(db, r, pubkey))
    }
    
    /// Get identity wot_id
    #[inline]
    pub fn get_wot_id_<DB: DbReadable, R: DbReader>(
        db: &DB,
        r: &R,
        pubkey: &PubKey,
    ) -> Result<Option<WotId>, DbError> {
        if let Some(v) = db
            .get_store(WOT_ID_INDEX)
            .get(r, &pubkey.to_bytes_vector())?
        {
            if let DbValue::U64(wot_id) = v {
                Ok(Some(WotId(wot_id as usize)))
            } else {
                Err(DbError::DBCorrupted)
            }
        } else {
            Ok(None)
        }
    }
    /// Get wot_id index
    pub fn get_wot_index<DB: DbReadable>(db: &DB) -> Result<HashMap<PubKey, WotId>, DbError> {
        db.read(|r| {
            let mut wot_index = HashMap::new();
            for entry in db.get_store(WOT_ID_INDEX).iter_start(r)? {
                let (k, v_opt) = entry?;
                if let Some(DbValue::U64(wot_id)) = v_opt {
                    wot_index.insert(
                        PubKey::from_bytes(k).map_err(|_| DbError::DBCorrupted)?,
                        WotId(wot_id as usize),
                    );
                }
            }
            Ok(wot_index)
        })
    }
    
    /// Get wot_uid index
    pub fn get_wot_uid_index<DB: DbReadable>(db: &DB) -> Result<HashMap<WotId, String>, DbError> {
        db.read(|r| {
            let mut wot_uid_index = HashMap::new();
            let greatest_wot_id = crate::current_meta_datas::get_greatest_wot_id_(db, r)?;
            for wot_id in 0..=greatest_wot_id.0 {
                if let Some(db_idty) = get_identity_by_wot_id_(db, r, WotId(wot_id))? {
                    wot_uid_index.insert(WotId(wot_id), db_idty.idty_doc.username().to_owned());
                }
            }
            Ok(wot_uid_index)
        })
    }
    
    #[cfg(test)]
    mod test {
    
        use super::*;
        use crate::current_meta_datas::CurrentMetaDataKey;
        use crate::paging::PagingFilter;
        use dubp_common_doc::Blockstamp;
        use dup_crypto_tests_tools::mocks::pubkey;
        use durs_common_tests_tools::collections::slice_same_elems;
        use durs_dbs_tools::kv_db::KvFileDbHandler;
    
        fn gen_mock_dal_idty(pubkey: PubKey, created_block_id: BlockNumber) -> DbIdentity {
            DbIdentity {
                hash: "".to_owned(),
                state: DbIdentityState::Member(vec![]),
                joined_on: Blockstamp::default(),
                expired_on: None,
                revoked_on: None,
                idty_doc: dubp_user_docs_tests_tools::mocks::identity::gen_mock_idty(
                    pubkey,
                    created_block_id,
                ),
                wot_id: WotId(0),
                ms_created_block_id: BlockNumber(0),
                ms_chainable_on: vec![],
                cert_chainable_on: vec![],
            }
        }
    
        #[test]
        fn test_get_identities() -> Result<(), DbError> {
            // Create mock identities
            let mock_identities = vec![
                gen_mock_dal_idty(pubkey('A'), BlockNumber(0)),
                gen_mock_dal_idty(pubkey('B'), BlockNumber(1)),
                gen_mock_dal_idty(pubkey('C'), BlockNumber(3)),
                gen_mock_dal_idty(pubkey('D'), BlockNumber(4)),
                gen_mock_dal_idty(pubkey('E'), BlockNumber(5)),
            ];
    
            // Write mock identities in DB
            let db = crate::tests::open_tmp_db()?;
            let mut wot_id = 0;
            for idty in &mock_identities {
                let idty_bin = durs_dbs_tools::to_bytes(idty)?;
                db.write(|mut w| {
                    db.get_store(WOT_ID_INDEX).put(
                        w.as_mut(),
                        &idty.idty_doc.issuers()[0].to_bytes_vector(),
                        &DbValue::U64(wot_id),
                    )?;
                    db.get_int_store(IDENTITIES).put(
                        w.as_mut(),
                        wot_id as u32,
                        &KvFileDbHandler::db_value(&idty_bin)?,
                    )?;
                    Ok(w)
                })?;
                wot_id += 1;
            }
    
            // Write greatest wot id
            db.write(|mut w| {
                db.get_int_store(CURRENT_METAS_DATAS).put(
                    w.as_mut(),
                    CurrentMetaDataKey::NextWotId.to_u32(),
                    &DbValue::U64(wot_id),
                )?;
                Ok(w)
            })?;
    
            // Test default filters
            let mut filters = IdentitiesFilter::default();
            assert!(slice_same_elems(
                &mock_identities,
                &get_identities(&db, filters, BlockNumber(5))?
            ));
            // Test by pubkey filter
            filters = IdentitiesFilter::by_pubkey(pubkey('A'));
            assert_eq!(
                vec![mock_identities[0].clone()],
                get_identities(&db, filters, BlockNumber(5))?
            );
            filters = IdentitiesFilter::by_pubkey(pubkey('C'));
            assert_eq!(
                vec![mock_identities[2].clone()],
                get_identities(&db, filters, BlockNumber(5))?
            );
    
            // Test paging filter with little page size
            filters = IdentitiesFilter {
                paging: PagingFilter {
                    from: BlockNumber(0),
                    to: None,
                    page_size: 2,
                    page_number: 1,
                },
                by_pubkey: None,
            };
            assert!(slice_same_elems(
                &vec![mock_identities[2].clone(), mock_identities[3].clone()],
                &get_identities(&db, filters, BlockNumber(5))?
            ));
    
            // Test paging filter with limited interval
            filters = IdentitiesFilter {
                paging: PagingFilter {
                    from: BlockNumber(2),
                    to: Some(BlockNumber(3)),
                    page_size: 50,
                    page_number: 0,
                },
                by_pubkey: None,
            };
            assert_eq!(
                vec![mock_identities[2].clone()],
                get_identities(&db, filters, BlockNumber(5))?
            );
    
            Ok(())
        }
    }