1use crate::log_info;
16use regex::Regex;
17use std::{
18 collections::BTreeMap,
19 path::PathBuf,
20};
21
22pub fn salt() -> Option<[u8; 32]> {
25 use funty::Fundamental as _;
26
27 let mut arr = [0u8; 32];
28 let t: [u8; 16] = std::time::SystemTime::now()
29 .duration_since(std::time::UNIX_EPOCH)
30 .unwrap_or_else(|err| panic!("unable to get unix time: {err}"))
31 .as_millis()
32 .as_u128()
33 .to_le_bytes();
34 arr[..16].copy_from_slice(t.as_slice());
35 arr[16..].copy_from_slice(t.as_slice());
36 Some(arr)
37}
38
39pub struct ContractsRegistry {
41 contracts: BTreeMap<String, PathBuf>,
42}
43
44impl ContractsRegistry {
45 pub fn new<P: Into<PathBuf>>(contracts: impl IntoIterator<Item = P>) -> Self {
47 let contracts = contracts
48 .into_iter()
49 .map(|path| {
50 let contract_binary_path: PathBuf = path.into();
51 let contract_name =
52 contract_binary_path.file_stem().unwrap_or_else(|| {
53 panic!(
54 "Invalid contract binary path `{}`",
55 contract_binary_path.display(),
56 )
57 });
58 (
59 contract_name.to_string_lossy().to_string(),
60 contract_binary_path,
61 )
62 })
63 .collect();
64
65 Self { contracts }
66 }
67
68 pub fn load_code(&self, contract: &str) -> Vec<u8> {
70 let contract_binary_path = self
71 .contracts
72 .iter().find_map(|(name, path)| {
73 let re = Regex::new(r"-features-.+$").expect("failed creating regex");
74 let key = re.replace_all(name, "");
75 if key == contract || key.replace('_', "-") == contract {
76 return Some(path);
77 }
78 None
79 })
80 .unwrap_or_else(||
81 panic!(
82 "Unknown contract {contract}. Available contracts: {:?}.\n\
83 For a contract to be built, add it as a dependency to the `Cargo.toml`",
84 self.contracts.keys()
85 )
86 );
87 let code = std::fs::read(contract_binary_path).unwrap_or_else(|err| {
88 panic!(
89 "Error loading '{}': {:?}",
90 contract_binary_path.display(),
91 err
92 )
93 });
94 log_info(&format!("{:?} has {} KiB", contract, code.len() / 1024));
95 code
96 }
97}
98
99pub fn code_hash(code: &[u8]) -> [u8; 32] {
101 h256_hash(code)
102}
103
104fn h256_hash(code: &[u8]) -> [u8; 32] {
106 use sha3::{
107 Digest,
108 Keccak256,
109 };
110 let hash = Keccak256::digest(code);
111 let sl = hash.as_slice();
112 assert!(sl.len() == 32, "expected length of 32");
113 let mut arr = [0u8; 32];
114 arr.copy_from_slice(sl);
115 arr
116}