1use crate::bindings::vm::*;
18use crate::cache::Cache;
19use crate::cache::CacheRawAPI;
20use crate::dataset::Dataset;
21use crate::dataset::DatasetRawAPI;
22use crate::errors::VmCreationError;
23use crate::flags::RandomXFlags;
24use crate::result_hash::ResultHash;
25use crate::result_hash::ToRawMut;
26use crate::try_alloc;
27use crate::RResult;
28
29#[derive(Debug)]
30pub struct RandomXVM<T> {
31 vm: *mut randomx_vm,
32 _state: T,
34}
35
36impl<T> RandomXVM<T>
37where
38 T: CacheRawAPI,
39{
40 pub fn light(cache: T, flags: RandomXFlags) -> RResult<Self> {
41 if !flags.is_light_mode() {
42 return Err(VmCreationError::IncorrectLightModeFlag { flags })?;
43 }
44
45 let vm = try_alloc! { randomx_create_vm(flags.bits(), cache.raw(), std::ptr::null_mut()), VmCreationError::AllocationFailed {flags} };
46
47 let vm = RandomXVM { vm, _state: cache };
48 Ok(vm)
49 }
50
51 pub fn set_new_cache(&mut self, cache: &'_ Cache) {
55 unsafe { randomx_vm_set_cache(self.vm, cache.raw()) }
56 }
57}
58
59impl<T> RandomXVM<T>
60where
61 T: DatasetRawAPI,
62{
63 pub fn fast(dataset: T, flags: RandomXFlags) -> RResult<Self> {
64 if !flags.is_fast_mode() {
65 return Err(VmCreationError::IncorrectFastModeFlag { flags })?;
66 }
67
68 let vm = try_alloc! { randomx_create_vm(flags.bits(), std::ptr::null_mut(), dataset.raw()), VmCreationError::AllocationFailed {flags} };
69
70 let vm = RandomXVM {
71 vm,
72 _state: dataset,
73 };
74
75 Ok(vm)
76 }
77
78 pub fn set_new_dataset(&mut self, dataset: &'_ Dataset) {
80 unsafe { randomx_vm_set_dataset(self.vm, dataset.raw()) }
81 }
82}
83
84impl<T> Drop for RandomXVM<T> {
85 fn drop(&mut self) {
86 unsafe { randomx_destroy_vm(self.vm) }
87 }
88}
89
90impl<T> RandomXVM<T> {
91 pub fn hash(&self, local_nonce: &[u8]) -> ResultHash {
93 let mut hash = ResultHash::empty();
94
95 unsafe {
96 randomx_calculate_hash(
97 self.vm,
98 local_nonce.as_ptr() as *const std::ffi::c_void,
99 local_nonce.len(),
100 hash.as_raw_mut(),
101 )
102 };
103
104 hash
105 }
106
107 pub fn hash_first(&self, local_nonce: &[u8]) {
109 unsafe {
110 randomx_calculate_hash_first(
111 self.vm,
112 local_nonce.as_ptr() as *const std::ffi::c_void,
113 local_nonce.len(),
114 )
115 };
116 }
117
118 pub fn hash_next(&self, local_nonce: &[u8]) -> ResultHash {
121 let mut hash = ResultHash::empty();
122
123 unsafe {
124 randomx_calculate_hash_next(
125 self.vm,
126 local_nonce.as_ptr() as *const std::ffi::c_void,
127 local_nonce.len(),
128 hash.as_raw_mut(),
129 )
130 };
131
132 hash
133 }
134
135 pub fn hash_last(&self) -> ResultHash {
137 let mut hash = ResultHash::empty();
138
139 unsafe { randomx_calculate_hash_last(self.vm, hash.as_raw_mut()) };
140
141 hash
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use crate::{Cache, Dataset, RandomXFlags, RandomXVM};
148
149 #[test]
150 fn light_no_creates_with_full_mem() {
151 let flags = RandomXFlags::recommended_full_mem();
152 let cache = Cache::new(&[0, 1], flags).unwrap();
153 let vm = RandomXVM::light(cache.handle(), flags);
154
155 assert!(vm.is_err());
156 }
157
158 #[test]
159 fn fast_no_creates_without_full_mem() {
160 let flags = RandomXFlags::recommended();
161 let dataset = Dataset::new(&[0, 1], flags).unwrap();
162 let vm = RandomXVM::fast(dataset.handle(), flags);
163
164 assert!(vm.is_err());
165 }
166}