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