Skip to content
This repository has been archived by the owner on Sep 13, 2022. It is now read-only.

Commit

Permalink
feat(service):add keccak256,verify in util service (#242)
Browse files Browse the repository at this point in the history
* add keccak256,verify in util service,

* fix pr review, add service err return, add test_verify

* fix ci check

* fix ci test sync because of ci machine performance

* modify e2e test, fix timeout bug
  • Loading branch information
cosinlink committed Apr 16, 2020
1 parent 0734799 commit 41cb601
Show file tree
Hide file tree
Showing 8 changed files with 335 additions and 29 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -37,6 +37,7 @@ tokio = { version = "0.2", features = ["macros", "rt-core", "rt-util", "signal",
[dev-dependencies]
asset = { path = "built-in-services/asset"}
metadata = { path = "built-in-services/metadata"}
util = { path = "built-in-services/util"}

[workspace]
members = [
Expand Down
27 changes: 27 additions & 0 deletions built-in-services/util/Cargo.toml
@@ -0,0 +1,27 @@
[package]
name = "util"
version = "0.1.0-alpha.0"
authors = ["Muta Dev <muta@nervos.org>"]
edition = "2018"
repository = "https://github.com/nervosnetwork/muta"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
binding-macro = { path = "../../binding-macro" }
protocol = { path = "../../protocol", package = "muta-protocol" }
hasher = { version="0.1", features = ["hash-keccak"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
rlp = "0.4"
bytes = "0.5"
derive_more = "0.15"
byteorder = "1.3"
common-crypto = { path = "../../common/crypto" }
hex = "0.4"
rand = "0.7"

[dev-dependencies]
cita_trie = "2.0"
async-trait = "0.1"
framework = { path = "../../framework" }
81 changes: 81 additions & 0 deletions built-in-services/util/src/lib.rs
@@ -0,0 +1,81 @@
use bytes::Bytes;
use hasher::{Hasher, HasherKeccak};

use binding_macro::{cycles, service};
use common_crypto::{Crypto, Secp256k1};
use protocol::traits::{ExecutorParams, ServiceResponse, ServiceSDK};
use protocol::types::{Hash, ServiceContext};

use crate::types::{KeccakPayload, KeccakResponse, SigVerifyPayload, SigVerifyResponse};

#[cfg(test)]
mod tests;
pub mod types;

pub struct UtilService<SDK> {
_sdk: SDK,
}

#[service]
impl<SDK: ServiceSDK> UtilService<SDK> {
pub fn new(_sdk: SDK) -> Self {
Self { _sdk }
}

#[cycles(100_00)]
#[read]
fn keccak256(
&self,
ctx: ServiceContext,
payload: KeccakPayload,
) -> ServiceResponse<KeccakResponse> {
let keccak = HasherKeccak::new();
let data = hex::decode(payload.hex_str.as_string_trim0x());
if data.is_err() {
return ServiceResponse::<KeccakResponse>::from_error(107, "data not valid".to_owned());
}

let hash_res = keccak.digest(data.unwrap().as_slice());
let response = KeccakResponse {
result: Hash::from_bytes(Bytes::from(hash_res)).unwrap(),
};
ServiceResponse::<KeccakResponse>::from_succeed(response)
}

#[cycles(100_00)]
#[read]
fn verify(
&self,
ctx: ServiceContext,
payload: SigVerifyPayload,
) -> ServiceResponse<SigVerifyResponse> {
let data_sig = hex::decode(payload.sig.as_string_trim0x());
if data_sig.is_err() {
return ServiceResponse::<SigVerifyResponse>::from_error(
108,
"signature not valid".to_owned(),
);
};

let data_pk = hex::decode(payload.pub_key.as_string_trim0x());
if data_pk.is_err() {
return ServiceResponse::<SigVerifyResponse>::from_error(
109,
"public key not valid".to_owned(),
);
};

let data_hash = payload.hash.as_bytes();

let response = SigVerifyResponse {
is_ok: Secp256k1::verify_signature(
data_hash.as_ref(),
data_sig.unwrap().as_slice(),
data_pk.unwrap().as_slice(),
)
.is_ok(),
};

ServiceResponse::<SigVerifyResponse>::from_succeed(response)
}
}
183 changes: 183 additions & 0 deletions built-in-services/util/src/tests/mod.rs
@@ -0,0 +1,183 @@
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;

use cita_trie::MemoryDB;
use rand::rngs::OsRng;

use async_trait::async_trait;
use common_crypto::{
Crypto, PrivateKey, PublicKey, Secp256k1, Secp256k1PrivateKey, Signature, ToPublicKey,
};
use framework::binding::sdk::{DefalutServiceSDK, DefaultChainQuerier};
use framework::binding::state::{GeneralServiceState, MPTTrie};
use protocol::traits::{NoopDispatcher, Storage};
use protocol::types::{
Address, Block, Hash, Hex, Proof, Receipt, ServiceContext, ServiceContextParams,
SignedTransaction,
};
use protocol::{types::Bytes, ProtocolResult};

use crate::types::{KeccakPayload, SigVerifyPayload};
use crate::UtilService;

#[test]
fn test_hash() {
let cycles_limit = 1024 * 1024 * 1024; // 1073741824
let caller = Address::from_hex("0x755cdba6ae4f479f7164792b318b2a06c759833b").unwrap();
let context = mock_context(cycles_limit, caller);

let service = new_util_service();

let res = service
.keccak256(context, KeccakPayload {
hex_str: Hex::from_string("0x1234".to_string()).unwrap(),
})
.succeed_data;

assert_eq!(
res.result.as_hex(),
"0x56570de287d73cd1cb6092bb8fdee6173974955fdef345ae579ee9f475ea7432".to_string()
)
}

#[test]
fn test_verify() {
let cycles_limit = 1024 * 1024 * 1024; // 1073741824
let caller = Address::from_hex("0x755cdba6ae4f479f7164792b318b2a06c759833b").unwrap();
let context = mock_context(cycles_limit, caller);

let service = new_util_service();

let priv_key = Secp256k1PrivateKey::generate(&mut OsRng);
let pub_key = priv_key.pub_key();

let mut input_pk: String = "0x".to_string();
input_pk.push_str(hex::encode(pub_key.to_bytes()).as_str());

let pub_key_data = Hex::from_string(input_pk).unwrap();
let hash = Hash::from_hex("0x56570de287d73cd1cb6092bb8fdee6173974955fdef345ae579ee9f475ea7432")
.unwrap();

let sig = Secp256k1::sign_message(&hash.as_bytes(), &priv_key.to_bytes()).unwrap();
let mut input_sig: String = "0x".to_string();
input_sig.push_str(hex::encode(sig.to_bytes()).as_str());
let sig_data = Hex::from_string(input_sig).unwrap();

println!(
"pubkey: {}\r\nsig: {}",
pub_key_data.as_string(),
sig_data.as_string()
);

let res = service
.verify(context, SigVerifyPayload {
hash,
sig: sig_data,
pub_key: pub_key_data,
})
.succeed_data;

assert_eq!(res.is_ok, true)
}

fn new_util_service() -> UtilService<
DefalutServiceSDK<
GeneralServiceState<MemoryDB>,
DefaultChainQuerier<MockStorage>,
NoopDispatcher,
>,
> {
let chain_db = DefaultChainQuerier::new(Arc::new(MockStorage {}));
let trie = MPTTrie::new(Arc::new(MemoryDB::new(false)));
let state = GeneralServiceState::new(trie);

let sdk = DefalutServiceSDK::new(
Rc::new(RefCell::new(state)),
Rc::new(chain_db),
NoopDispatcher {},
);

UtilService::new(sdk)
}

fn mock_context(cycles_limit: u64, caller: Address) -> ServiceContext {
let params = ServiceContextParams {
tx_hash: None,
nonce: None,
cycles_limit,
cycles_price: 1,
cycles_used: Rc::new(RefCell::new(0)),
caller,
height: 1,
timestamp: 0,
service_name: "service_name".to_owned(),
service_method: "service_method".to_owned(),
service_payload: "service_payload".to_owned(),
extra: None,
events: Rc::new(RefCell::new(vec![])),
};

ServiceContext::new(params)
}

struct MockStorage;

#[async_trait]
impl Storage for MockStorage {
async fn insert_transactions(&self, _: Vec<SignedTransaction>) -> ProtocolResult<()> {
unimplemented!()
}

async fn insert_block(&self, _: Block) -> ProtocolResult<()> {
unimplemented!()
}

async fn insert_receipts(&self, _: Vec<Receipt>) -> ProtocolResult<()> {
unimplemented!()
}

async fn update_latest_proof(&self, _: Proof) -> ProtocolResult<()> {
unimplemented!()
}

async fn get_transaction_by_hash(&self, _: Hash) -> ProtocolResult<SignedTransaction> {
unimplemented!()
}

async fn get_transactions(&self, _: Vec<Hash>) -> ProtocolResult<Vec<SignedTransaction>> {
unimplemented!()
}

async fn get_latest_block(&self) -> ProtocolResult<Block> {
unimplemented!()
}

async fn get_block_by_height(&self, _: u64) -> ProtocolResult<Block> {
unimplemented!()
}

async fn get_block_by_hash(&self, _: Hash) -> ProtocolResult<Block> {
unimplemented!()
}

async fn get_receipt(&self, _: Hash) -> ProtocolResult<Receipt> {
unimplemented!()
}

async fn get_receipts(&self, _: Vec<Hash>) -> ProtocolResult<Vec<Receipt>> {
unimplemented!()
}

async fn get_latest_proof(&self) -> ProtocolResult<Proof> {
unimplemented!()
}

async fn update_overlord_wal(&self, _info: Bytes) -> ProtocolResult<()> {
unimplemented!()
}

async fn load_overlord_wal(&self) -> ProtocolResult<Bytes> {
unimplemented!()
}
}
24 changes: 24 additions & 0 deletions built-in-services/util/src/types.rs
@@ -0,0 +1,24 @@
use protocol::types::{Hash, Hex};
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct KeccakPayload {
pub hex_str: Hex,
}

#[derive(Deserialize, Serialize, Clone, Debug, Default)]
pub struct KeccakResponse {
pub result: Hash,
}

#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct SigVerifyPayload {
pub hash: Hash,
pub sig: Hex,
pub pub_key: Hex,
}

#[derive(Deserialize, Serialize, Clone, Debug, Default)]
pub struct SigVerifyResponse {
pub is_ok: bool,
}
4 changes: 3 additions & 1 deletion examples/muta-chain.rs
Expand Up @@ -4,6 +4,7 @@ use metadata::MetadataService;
use muta::MutaBuilder;
use protocol::traits::{Service, ServiceMapping, ServiceSDK};
use protocol::{ProtocolError, ProtocolErrorKind, ProtocolResult};
use util::UtilService;

struct DefaultServiceMapping;

Expand All @@ -16,6 +17,7 @@ impl ServiceMapping for DefaultServiceMapping {
let service = match name {
"asset" => Box::new(AssetService::new(sdk)) as Box<dyn Service>,
"metadata" => Box::new(MetadataService::new(sdk)) as Box<dyn Service>,
"util" => Box::new(UtilService::new(sdk)) as Box<dyn Service>,
_ => {
return Err(MappingError::NotFoundService {
service: name.to_owned(),
Expand All @@ -28,7 +30,7 @@ impl ServiceMapping for DefaultServiceMapping {
}

fn list_service_name(&self) -> Vec<String> {
vec!["asset".to_owned(), "metadata".to_owned()]
vec!["asset".to_owned(), "metadata".to_owned(), "util".to_owned()]
}
}

Expand Down
1 change: 1 addition & 0 deletions framework/Cargo.toml
Expand Up @@ -11,6 +11,7 @@ repository = "https://github.com/nervosnetwork/muta"
protocol = { path = "../protocol", package = "muta-protocol" }
asset = { path = "../built-in-services/asset"}
metadata = { path = "../built-in-services/metadata"}
util = { path = "../built-in-services/util"}

hasher = { version = "0.1", features = ['hash-keccak'] }
cita_trie = "2.0"
Expand Down

0 comments on commit 41cb601

Please sign in to comment.