cm_contract_sdk 0.0.2

cm contract sdk for studty
Documentation
// use serde::{Deserialize, Serialize};
use tiny_keccak::{Hasher, Keccak};

use crate::{
    easycodec::EasyCodec,
    sim_context::{self, SimContext},
};

const KEY_NAME: &str = "name";
const KEY_DEPTH: &str = "depth";

// #[derive(Serialize, Deserialize)]
pub struct StoreMap<'a, C>
where
    C: SimContext,
{
    name: String,
    depth: i64,
    // hash_type:
    ctx: &'a C,
}

impl<C: SimContext> StoreMap<'_, C> {
    pub fn new<'a>(ctx: &'a C, name: &str, depth: i64) -> Result<StoreMap<'a, C>, String> {
        if depth <= 0 {
            return Err("depth must be greater than zero".to_string());
        }

        if name.is_empty() {
            return Err("name cannot be empty".to_string());
        }

        let map_key = get_hash(name.as_bytes());

        let mut state_key = name.to_string();
        state_key.push_str(map_key.as_str());

        let data = match ctx.get_state(state_key.as_str(), "") {
            Ok(data) => data,
            Err(_) => return Err("get state faile.".to_string()),
        };

        let store_map;
        if data.len() != 0 {
            let ec = EasyCodec::new_with_bytes(&data);
            store_map = StoreMap {
                name: ec.get_string(KEY_NAME).unwrap(),
                depth: ec.get_i64(KEY_DEPTH).unwrap(),
                ctx,
            }
        } else {
            store_map = StoreMap {
                name: name.to_string(),
                depth,
                ctx,
            };
            match store_map.save(state_key.as_str()) {
                Ok(_) => {}
                Err(e) => return Err(e),
            }
        }

        Ok(store_map)
    }

    fn save(&self, state_key: &str) -> Result<(), String> {
        let mut ec = EasyCodec::new();
        ec.add_string(KEY_NAME, &self.name);
        ec.add_i64(KEY_DEPTH, self.depth);

        let data = ec.marshal();

        if self.ctx.put_state(state_key, "", &data) != sim_context::SUCCESS_CODE {
            return Err("failed to put state".to_string());
        }

        Ok(())
    }

    fn check_depth(&self, key: &Vec<String>) -> Option<String> {
        for k in key {
            if k.is_empty() {
                return Some("key cannot be empty".to_string());
            }
        }
        if self.depth != (key.len() as i64) {
            return Some("please check keys".to_string());
        }

        None
    }

    fn generate_key(&self, key: &Vec<String>) -> (String, String) {
        let mut field = get_hash(self.name.as_bytes());
        for k in key {
            field.push_str(k);
            field = get_hash(field.as_bytes());
        }
        // let gened_key = key.join("");
        let mut gened_key = self.name.clone();

        let end_key = key.join("");
        gened_key.push_str(end_key.as_str());

        (gened_key, field)
    }

    pub fn get(&self, key: &Vec<String>) -> Result<Vec<u8>, String> {
        if let Some(e) = self.check_depth(key) {
            return Err(e);
        }

        let (gened_key, field) = self.generate_key(key);

        match self.ctx.get_state(&gened_key, &field) {
            Ok(res) => Ok(res),
            Err(_) => Err("get state fail".to_string()),
        }
    }

    pub fn set(&self, key: &Vec<String>, value: &[u8]) -> Result<(), String> {
        if let Some(e) = self.check_depth(key) {
            return Err(e);
        };

        let (gened_key, field) = self.generate_key(key);

        let re = self.ctx.put_state(&gened_key, &field, value);
        if re != sim_context::SUCCESS_CODE {
            return Err("failed to put state".to_string());
        }

        Ok(())
    }

    pub fn del(&self, key: &Vec<String>) -> Result<(), String> {
        if let Some(e) = self.check_depth(key) {
            return Err(e);
        }

        let (gened_key, field) = self.generate_key(key);

        if self.ctx.delete_state(&gened_key, &field) != sim_context::SUCCESS_CODE {
            return Err("failed to del state".to_string());
        }

        Ok(())
    }

    pub fn exist(&self, key: &Vec<String>) -> Result<bool, String> {
        if let Some(e) = self.check_depth(key) {
            return Err(e);
        }

        let (gened_key, field) = self.generate_key(key);
        match self.ctx.get_state(&gened_key, &field) {
            Ok(data) => {
                if data.len() > 0 {
                    return Ok(true);
                }
            }
            Err(_) => return Err("failed to get state".to_string()),
        }

        Ok(false)
    }
}

fn get_hash(data: &[u8]) -> String {
    let mut keccak = Keccak::v256();
    keccak.update(data);

    let mut output = [0u8; 32];
    keccak.finalize(&mut output);

    hex::encode(output)
}