Skip to content

Commit eca7499

Browse files
committed
create a MethodHasher according to filecoin-project/FIPs#382
1 parent 1c37788 commit eca7499

File tree

4 files changed

+94
-8
lines changed

4 files changed

+94
-8
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Generated by Cargo
22
# will have compiled files and executables
3-
/target/
3+
target/
44

55
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
66
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html

fvm_dispatch/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9+
fvm_sdk = { version = "1.0.0" }

fvm_dispatch/src/hash.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use fvm_sdk::crypto;
2+
3+
/// Minimal interface for a hashing function
4+
///
5+
/// Hasher::hash() must return a digest that is at least 4 bytes long so that it can be cast to a u32
6+
pub trait Hasher {
7+
/// For an input of bytes return a digest that is at least 4 bytes long
8+
fn hash(&self, bytes: &[u8]) -> Vec<u8>;
9+
}
10+
11+
/// Hasher that uses the hash_blake2b syscall provided by the FVM
12+
#[derive(Default)]
13+
pub struct Blake2bSyscall {}
14+
15+
impl Hasher for Blake2bSyscall {
16+
fn hash(&self, bytes: &[u8]) -> Vec<u8> {
17+
crypto::hash_blake2b(bytes).try_into().unwrap()
18+
}
19+
}
20+
21+
#[derive(Default)]
22+
pub struct MethodHasher<T: Hasher> {
23+
hasher: T,
24+
}
25+
26+
impl<T: Hasher> MethodHasher<T> {
27+
const CONSTRUCTOR_METHOD_NAME: &'static str = "Constructor";
28+
const CONSTRUCTOR_METHOD_NUMBER: u64 = 1_u64;
29+
pub fn new(hasher: T) -> Self {
30+
Self { hasher }
31+
}
32+
33+
pub fn method_number(&self, method_name: &str) -> u64 {
34+
if method_name == Self::CONSTRUCTOR_METHOD_NAME {
35+
Self::CONSTRUCTOR_METHOD_NUMBER
36+
} else {
37+
let digest = self.hasher.hash(method_name.as_bytes());
38+
if digest.len() < 4 {
39+
panic!("Invalid hasher used: digest must be at least 4 bytes long");
40+
}
41+
as_u32(digest.as_slice()) as u64
42+
}
43+
}
44+
}
45+
46+
/// Takes a byte array and interprets it as a u32 number
47+
/// Assumes little-endian order
48+
#[rustfmt::skip]
49+
fn as_u32(bytes: &[u8]) -> u32 {
50+
((bytes[0] as u32) << (8 * 3)) +
51+
((bytes[1] as u32) << (8 * 2)) +
52+
((bytes[2] as u32) << (8 * 1)) +
53+
(bytes[3] as u32)
54+
}
55+
56+
#[cfg(test)]
57+
mod tests {
58+
59+
use super::{Blake2bSyscall, Hasher, MethodHasher};
60+
61+
#[derive(Clone, Copy)]
62+
struct FakeHasher {}
63+
impl Hasher for FakeHasher {
64+
fn hash(&self, bytes: &[u8]) -> Vec<u8> {
65+
return bytes.to_vec();
66+
}
67+
}
68+
69+
#[test]
70+
#[allow(unused)]
71+
fn compile() {
72+
let method_hasher = MethodHasher::new(Blake2bSyscall {});
73+
}
74+
75+
#[test]
76+
fn constructor_method_number() {
77+
let method_hasher = MethodHasher::new(FakeHasher {});
78+
assert_eq!(method_hasher.method_number("Constructor"), 1);
79+
}
80+
81+
#[test]
82+
fn normal_method_number() {
83+
let fake_hasher = FakeHasher {};
84+
let method_hasher = MethodHasher::new(fake_hasher);
85+
assert_eq!(
86+
method_hasher.method_number("NormalMethod"),
87+
super::as_u32(&fake_hasher.hash(b"NormalMethod")) as u64
88+
);
89+
}
90+
}

fvm_dispatch/src/lib.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1+
pub mod hash;
12
#[cfg(test)]
2-
mod tests {
3-
#[test]
4-
fn it_works() {
5-
let result = 2 + 2;
6-
assert_eq!(result, 4);
7-
}
8-
}
3+
mod tests {}

0 commit comments

Comments
 (0)