From cd4e1c2c7020cd651d0d25f8586a0905db2f7e0f Mon Sep 17 00:00:00 2001 From: ImmortalOctogen Date: Mon, 20 Nov 2023 18:52:45 +0300 Subject: [PATCH] Reformatted code, updated dependencies and new hashrate metrics --- .gitignore | 1 - Cargo.lock | 505 ---------- Cargo.toml | 3 +- "\\" | 63 -- rust-randomx/.circleci/config.yml | 28 - rust-randomx/.gitignore | 16 - rust-randomx/Cargo.toml | 24 - rust-randomx/LICENSE | 29 - rust-randomx/README.md | 39 - rust-randomx/build.rs | 159 --- rust-randomx/src/bindings.rs | 335 ------- rust-randomx/src/lib.rs | 631 ------------ rust-randomx/test | 0 src/block.rs | 94 +- src/hashing.rs | 1 + src/hexbytes.rs | 12 +- src/login.json | 64 -- src/main.rs | 113 ++- src/miner.rs | 80 +- src/randomx/hash.rs | 79 +- src/randomx/m128.rs | 4 +- src/randomx/memory.rs | 46 +- src/randomx/program.rs | 5 +- src/randomx/superscalar.rs | 1549 +++++++++++++++-------------- src/randomx/vm.rs | 98 +- src/request.rs | 11 +- src/save.txt | 48 - src/tcp.rs | 46 +- 28 files changed, 1116 insertions(+), 2967 deletions(-) delete mode 100644 .gitignore delete mode 100644 Cargo.lock delete mode 100644 "\\" delete mode 100644 rust-randomx/.circleci/config.yml delete mode 100644 rust-randomx/.gitignore delete mode 100644 rust-randomx/Cargo.toml delete mode 100644 rust-randomx/LICENSE delete mode 100644 rust-randomx/README.md delete mode 100644 rust-randomx/build.rs delete mode 100644 rust-randomx/src/bindings.rs delete mode 100644 rust-randomx/src/lib.rs delete mode 100644 rust-randomx/test delete mode 100644 src/login.json delete mode 100644 src/save.txt diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ea8c4bf..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index bad2ae1..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,505 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" -dependencies = [ - "serde", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "constant_time_eq 0.1.5", -] - -[[package]] -name = "blake2b_simd" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" -dependencies = [ - "arrayref", - "arrayvec 0.7.2", - "constant_time_eq 0.2.5", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "constant_time_eq" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" - -[[package]] -name = "crossbeam-utils" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto_miner" -version = "0.1.0" -dependencies = [ - "arrayvec 0.7.2", - "blake2b_simd 1.0.1", - "byteorder", - "hex", - "rust-argon2", - "serde", - "serde_derive", - "serde_json", - "strum", - "tokio", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "libc" -version = "0.2.141" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "mio" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "proc-macro2" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "git+https://github.com/Ragnaroek/rust-argon2#b54e4eaa9188b7d809b6f840b67b8000491c6bc4" -dependencies = [ - "base64", - "blake2b_simd 0.5.11", - "constant_time_eq 0.1.5", - "crossbeam-utils", -] - -[[package]] -name = "rustversion" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "serde" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" - -[[package]] -name = "serde_derive" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "serde_json" -version = "1.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tokio" -version = "1.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" -dependencies = [ - "autocfg", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-macros" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" diff --git a/Cargo.toml b/Cargo.toml index 34e8ad4..20e2c30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ hex = "0.4.3" serde = "1.0.160" serde_derive = "1.0.160" serde_json = "1.0.96" -strum = {version = "0.24.1", features = ["derive"]} +strum = {version = "0.25.0", features = ["derive"]} tokio = { version = "1.27.0", features = ["full","sync"] } rust-argon2 = { git = "https://github.com/Ragnaroek/rust-argon2" } +stopwatch = "0.0.7" \ No newline at end of file diff --git "a/\\" "b/\\" deleted file mode 100644 index 91cf137..0000000 --- "a/\\" +++ /dev/null @@ -1,63 +0,0 @@ -use crate::request; -use tokio::sync::mpsc::UnboundedReceiver; -use serde::{Serialize,Deserialize}; -use std::net::TcpStream; -use std::{ - sync::{Arc,atomic::{Ordering, AtomicUsize},Mutex}, - thread::sleep, - time::Duration, - io::{self,Write,Cursor, Read, BufWriter,BufRead, BufReader}, - cmp::min, fmt::format, ops::{Deref, Index} -}; - -type BoxError = Box; - -pub fn connect(addr:&str,request:request::Request) -> Result { - let mut stream = TcpStream::connect(addr)?; - stream.set_nodelay(true)?; - serde_json::to_writer(&mut stream, &request)?; - writeln!(&mut stream)?; - stream.flush()?; - Ok(stream) -} - -pub struct Client { - pub stream:TcpStream, - pub reciever:UnboundedReceiver, -} -impl Client { - pub fn send<'a,T>(&mut self,request:request::Request<'a,T>) -> Result<(),BoxError> - where T:Serialize + Deserialize<'a> + std::fmt::Debug - { - serde_json::to_writer(&mut self.stream, &request).unwrap(); - writeln!(&mut self.stream).unwrap(); - self.stream.flush().unwrap(); - Ok(()) - } - pub fn message_listener(&mut self) { - loop { - if let Some(msg) = self.reciever.blocking_recv() { - match msg { - request::MessageType::Submit(submit) => { - println!("recieved share"); - let request = request::Request { - id:1, - method:"submit".to_string(), - params:&submit - }; - self.send(request).unwrap(); - println!("submitted share"); - }, - request::MessageType::KeepAlive(keep_alive) => { - let req = request::Request { - id:1, - method:"keepalived".to_string(), - params: &keep_alive - }; - self.send(req).unwrap(); - }, - } - } - } - } -} diff --git a/rust-randomx/.circleci/config.yml b/rust-randomx/.circleci/config.yml deleted file mode 100644 index 1f06189..0000000 --- a/rust-randomx/.circleci/config.yml +++ /dev/null @@ -1,28 +0,0 @@ -version: 2 - -defaults: - rust_image: &rust_image quay.io/tarilabs/rust_tari-build-with-deps:nightly-2019-09-13 - -jobs: - tests: - docker: - - image: *rust_image - steps: - - checkout - - run: - name: RandomX-rs source code - command: | - TOOLCHAIN_VERSION=nightly-2019-09-13 - rustup component add --toolchain $TOOLCHAIN_VERSION rustfmt - cargo fmt --all -- --check - cargo test --all - cargo test --release - -workflows: - version: 2 - workflow: - jobs: - - tests: - filters: - branches: - ignore: gh-pages diff --git a/rust-randomx/.gitignore b/rust-randomx/.gitignore deleted file mode 100644 index d217401..0000000 --- a/rust-randomx/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -/target/ - -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - -# These are backup files generated by rustfmt -**/*.rs.bk -.DS_Store -.idea -*.iml - -# randomX source code -randomx \ No newline at end of file diff --git a/rust-randomx/Cargo.toml b/rust-randomx/Cargo.toml deleted file mode 100644 index 275673b..0000000 --- a/rust-randomx/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "rust-randomx" -description = "Rust bindings for the RandomX Proof-of-Work" -authors = ["The Tari Development Community"] -repository = "https://github.com/tari-project/randomx-rs" -homepage = "https://tari.com" -readme = "README.md" -license = "BSD-3-Clause" -version = "0.4.0" -edition = "2018" -build="build.rs" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -# Create a dynamic library for C usage and a rust library so it can be called from rust -crate-type = ["cdylib","lib"] - -[dependencies] -libc = "0.2.62" -derive-error = "0.0.4" -bitflags = "1.2.1" - -[build-dependencies] -git2 = "0.8" diff --git a/rust-randomx/LICENSE b/rust-randomx/LICENSE deleted file mode 100644 index 64d9899..0000000 --- a/rust-randomx/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2019, The Tari Project -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/rust-randomx/README.md b/rust-randomx/README.md deleted file mode 100644 index b4d37cd..0000000 --- a/rust-randomx/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# randomx-rs -Rust bindings to the RandomX proof-of-work (Pow) system - -## Build Dependencies -### Mac -Install [XCode](https://apps.apple.com/za/app/xcode/id497799835?mt=12) and then the XCode Command Line Tools with the following command -``` -xcode-select --install -``` -For macOS Mojave additional headers need to be installed, run -``` -open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -``` -and follow the prompts - -Install Brew -``` -/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" -``` -Run the following to install needed bottles -``` -brew install git -brew install cmake -``` - -### Linux -Run the following to install dependencies -``` -apt-get install git cmake libc++-dev libc++abi-dev -``` - -### Windows - -Install [Git](https://git-scm.com/download/win) - -Install [CMake](https://cmake.org/download/) - -Install [Build Tools for Visual Studio 2019]( -https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16) diff --git a/rust-randomx/build.rs b/rust-randomx/build.rs deleted file mode 100644 index bc49ef6..0000000 --- a/rust-randomx/build.rs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2019. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -extern crate git2; - -use git2::{Cred, Oid, Repository}; -use std::env; -use std::fs::create_dir_all; -use std::io::Write; -use std::path::Path; -use std::process::Command; - -fn main() { - const RANDOMX_COMMIT: &str = "ac574e3743b00680445994cbe2c38ba0f52db70d"; - - let out_dir = env::var("OUT_DIR").unwrap(); - let project_dir = Path::new(&out_dir); - - let repo_dir = project_dir.join("randomx"); - - if !repo_dir.exists() { - create_dir_all(&repo_dir.to_str().unwrap()).unwrap(); - - // If we're inside CircleCI, use SSH (Circle requires this), otherwise good ol' https will do just fine - let repo = match env::var("CIRCLECI") { - Ok(v) if &v == "true" => build_using_ssh(&repo_dir), - _ => build_using_https(&repo_dir), - }; - - let oid = Oid::from_str(RANDOMX_COMMIT).unwrap(); - let commit = repo.find_commit(oid).unwrap(); - - let _branch = repo.branch(RANDOMX_COMMIT, &commit, false); - - let obj = repo - .revparse_single(&("refs/heads/".to_owned() + RANDOMX_COMMIT)) - .unwrap(); - - repo.checkout_tree(&obj, None).unwrap(); - - repo.set_head(&("refs/heads/".to_owned() + RANDOMX_COMMIT)) - .unwrap(); - } - - env::set_current_dir(Path::new(&repo_dir)).unwrap(); //change current path to repo for dependency build - let target = env::var("TARGET").unwrap(); - if target.contains("windows") { - let c = Command::new("cmake") - .arg("-G") - .arg("Visual Studio 16 2019") - .arg(".") - .output() - .expect("failed to execute CMake"); - println!("status: {}", c.status); - std::io::stdout().write_all(&c.stdout).unwrap(); - std::io::stderr().write_all(&c.stderr).unwrap(); - assert!(c.status.success()); - - let m = Command::new("cmake") - .arg("--build") - .arg(".") - .arg("--config") - .arg("Release") - .output() - .expect("failed to execute Make"); - println!("status: {}", m.status); - std::io::stdout().write_all(&m.stdout).unwrap(); - std::io::stderr().write_all(&m.stderr).unwrap(); - assert!(m.status.success()); - } else { - let c = Command::new("cmake") - .arg(".") - .output() - .expect("failed to execute CMake"); - println!("status: {}", c.status); - std::io::stdout().write_all(&c.stdout).unwrap(); - std::io::stderr().write_all(&c.stderr).unwrap(); - assert!(c.status.success()); - let m = Command::new("make") - .output() - .expect("failed to execute Make"); - println!("status: {}", m.status); - std::io::stdout().write_all(&m.stdout).unwrap(); - std::io::stderr().write_all(&m.stderr).unwrap(); - assert!(m.status.success()); - } - - env::set_current_dir(Path::new(&project_dir)).unwrap(); //change path back to main project - - if target.contains("windows") { - let include = &repo_dir.join("Release"); - println!( - "cargo:rustc-link-search=native={}", - &include.to_str().unwrap() - ); - println!("cargo:rustc-link-lib=static=randomx"); - } else { - println!( - "cargo:rustc-link-search=native={}", - &repo_dir.to_str().unwrap() - ); - println!("cargo:rustc-link-lib=randomx"); - } //link to RandomX - - if target.contains("apple") { - println!("cargo:rustc-link-lib=dylib=c++"); - } else if target.contains("linux") { - println!("cargo:rustc-link-lib=dylib=stdc++"); - } else if target.contains("windows") { - //println!("cargo:rustc-link-lib=dylib=c++"); - } else { - unimplemented!(); - } -} - -fn build_using_ssh(path: &Path) -> Repository { - let url = "ssh://git@github.com/tevador/RandomX.git"; - // Build up auth credentials via fetch options: - let mut cb = git2::RemoteCallbacks::new(); - cb.credentials(|_, _, _| { - let credentials = Cred::ssh_key_from_agent("git").expect("Could not get SSH key"); - Ok(credentials) - }); - let mut fo = git2::FetchOptions::new(); - fo.remote_callbacks(cb); - - let mut builder = git2::build::RepoBuilder::new(); - builder.fetch_options(fo); - match builder.clone(url, &path) { - Ok(repo) => repo, - Err(e) => panic!("Failed to clone RandomX: {}", e), - } -} - -fn build_using_https(path: &Path) -> Repository { - let url = "https://github.com/tevador/RandomX.git"; - match Repository::clone(url, &path) { - Ok(repo) => repo, - Err(e) => panic!("Failed to clone RandomX: {}", e), - } -} diff --git a/rust-randomx/src/bindings.rs b/rust-randomx/src/bindings.rs deleted file mode 100644 index 03a9d58..0000000 --- a/rust-randomx/src/bindings.rs +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2019. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -extern crate libc; - -use libc::{c_uint, c_ulong, c_void}; -pub const RANDOMX_HASH_SIZE: u32 = 32; -pub const RANDOMX_DATASET_ITEM_SIZE: u32 = 64; - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct randomx_dataset { - _unused: [u8; 0], -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct randomx_cache { - _unused: [u8; 0], -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct randomx_vm { - _unused: [u8; 0], -} - -extern "C" { - pub fn randomx_alloc_cache(flags: c_uint) -> *mut randomx_cache; - pub fn randomx_init_cache(cache: *mut randomx_cache, key: *const c_void, keySize: usize); - pub fn randomx_release_cache(cache: *mut randomx_cache); - pub fn randomx_alloc_dataset(flags: c_uint) -> *mut randomx_dataset; - pub fn randomx_dataset_item_count() -> c_ulong; - pub fn randomx_init_dataset( - dataset: *mut randomx_dataset, - cache: *mut randomx_cache, - start_item: c_ulong, - item_count: c_ulong, - ); - pub fn randomx_get_dataset_memory(dataset: *mut randomx_dataset) -> *mut c_void; - pub fn randomx_release_dataset(dataset: *mut randomx_dataset); - pub fn randomx_create_vm( - flags: c_uint, - cache: *mut randomx_cache, - dataset: *mut randomx_dataset, - ) -> *mut randomx_vm; - pub fn randomx_vm_set_cache(machine: *mut randomx_vm, cache: *mut randomx_cache); - pub fn randomx_vm_set_dataset(machine: *mut randomx_vm, dataset: *mut randomx_dataset); - pub fn randomx_destroy_vm(machine: *mut randomx_vm); - pub fn randomx_calculate_hash( - machine: *mut randomx_vm, - input: *const c_void, - input_size: usize, - output: *mut c_void, - ); - pub fn randomx_calculate_hash_first( - machine: *mut randomx_vm, - input: *const c_void, - input_size: usize, - ); - pub fn randomx_calculate_hash_next( - machine: *mut randomx_vm, - input_next: *const c_void, - input_size_next: usize, - output: *mut c_void, - ); - pub fn randomx_calculate_hash_last(machine: *mut randomx_vm, output: *mut c_void); - pub fn randomx_get_flags() -> c_uint; -} - -#[cfg(test)] -mod tests { - use super::*; - use libc::{c_char, c_uint, c_void}; - use std::ffi::CString; - use std::mem; - use std::ptr; - - type ArrType = [c_char; RANDOMX_HASH_SIZE as usize]; // arr_type is the type in C - - #[test] - fn alloc_cache() { - let key = "Key"; - let c_key = CString::new(key).unwrap(); - let c_key_ptr = c_key.as_bytes().as_ptr() as *mut c_void; - let flag: c_uint = 0; - let cache = unsafe { randomx_alloc_cache(flag) }; - let size_key = c_key.as_bytes().len() * mem::size_of::<*const c_char>(); - - unsafe { - randomx_init_cache(cache, c_key_ptr, size_key); - } - if cache.is_null() { - panic!("Failed to init cache"); - } - unsafe { - randomx_release_cache(cache); - } - } - - #[test] - fn alloc_dataset() { - let key = "Key"; - let c_key = CString::new(key).unwrap(); - let c_key_ptr = c_key.as_bytes().as_ptr() as *mut c_void; - let flag: c_uint = 0; - let cache = unsafe { randomx_alloc_cache(flag) }; - let size_key = c_key.as_bytes().len() * mem::size_of::<*const c_char>(); - - unsafe { - randomx_init_cache(cache, c_key_ptr, size_key); - } - - let dataset = unsafe { randomx_alloc_dataset(flag) }; - - unsafe { - randomx_init_dataset( - dataset, - cache, - 0, - (RANDOMX_DATASET_ITEM_SIZE - 1) as c_ulong, - ) - } - - assert_ne!(unsafe { randomx_dataset_item_count() }, 0); - - unsafe { - randomx_release_dataset(dataset); - randomx_release_cache(cache); - } - } - - #[test] - fn alloc_vm() { - let key = "Key"; - let flag: c_uint = 0; - - let c_key = CString::new(key).unwrap(); - let c_key_ptr = c_key.as_bytes().as_ptr() as *mut c_void; - - let cache = unsafe { randomx_alloc_cache(flag) }; - let size_key = c_key.as_bytes().len() * mem::size_of::<*const c_char>(); - - unsafe { - randomx_init_cache(cache, c_key_ptr, size_key); - } - let mut vm = unsafe { randomx_create_vm(flag, cache, ptr::null_mut()) }; - if vm.is_null() { - panic!("Failed to init vm with cache"); - } - unsafe { - randomx_vm_set_cache(vm, cache); - } - if vm.is_null() { - panic!("Failed to re-init vm with new cache"); - } - let dataset = unsafe { randomx_alloc_dataset(flag) }; - unsafe { - randomx_init_dataset( - dataset, - cache, - 0, - (RANDOMX_DATASET_ITEM_SIZE - 1) as c_ulong, - ) - } - vm = unsafe { randomx_create_vm(flag, cache, dataset) }; - if vm.is_null() { - panic!("Failed to init vm with dataset"); - } - unsafe { - randomx_vm_set_dataset(vm, dataset); - } - if vm.is_null() { - panic!("Failed to re-init vm with new dataset"); - } - unsafe { - randomx_release_dataset(dataset); - randomx_release_cache(cache); - randomx_destroy_vm(vm); - } - } - - #[test] - fn calculate_hash() { - let key = "Key"; - let input = "Input"; - - let flag: c_uint = 0; - - let c_key = CString::new(key).unwrap(); - let c_input = CString::new(input).unwrap(); - let c_key_ptr = c_key.as_bytes().as_ptr() as *mut c_void; - let c_input_ptr = c_input.as_bytes().as_ptr() as *mut c_void; - - let arr: ArrType = [0; RANDOMX_HASH_SIZE as usize]; - let output_ptr = arr.as_ptr() as *mut c_void; - - let cache = unsafe { randomx_alloc_cache(flag) }; - let size_key = c_key.as_bytes().len() * mem::size_of::<*const c_char>(); - let size_input = c_input.as_bytes().len() * mem::size_of::<*const c_char>(); - - unsafe { - randomx_init_cache(cache, c_key_ptr, size_key); - } - - let dataset = unsafe { randomx_alloc_dataset(flag) }; - - unsafe { randomx_init_dataset(dataset, cache, 0, (RANDOMX_DATASET_ITEM_SIZE - 1).into()) } - - let vm = unsafe { randomx_create_vm(flag, cache, ptr::null_mut()) }; - - unsafe { - randomx_calculate_hash(vm, c_input_ptr, size_input, output_ptr); - } - - let mut vec = Vec::new(); - let mut vec2 = Vec::new(); - - for i in 0..RANDOMX_HASH_SIZE { - vec.push(arr[i as usize] as u8); - vec2.push(0u8); - } - assert_ne!(vec, vec2); //vec2 is filled with 0 - unsafe { - randomx_destroy_vm(vm); - randomx_release_cache(cache); - } - } - - #[test] - fn calculate_hash_set() { - let key = "Key"; - let input = "Input"; - let input2 = "Input 2"; - let input3 = "Input 3"; - - let flag: c_uint = 0; - - let c_key = CString::new(key).unwrap(); - let c_input = CString::new(input).unwrap(); - let c_input2 = CString::new(input2).unwrap(); - let c_input3 = CString::new(input3).unwrap(); - let c_key_ptr = c_key.as_bytes().as_ptr() as *mut c_void; - let c_input_ptr = c_input.as_bytes().as_ptr() as *mut c_void; - let c_input_ptr2 = c_input2.as_bytes().as_ptr() as *mut c_void; - let c_input_ptr3 = c_input3.as_bytes().as_ptr() as *mut c_void; - - let arr: ArrType = [0; RANDOMX_HASH_SIZE as usize]; - let output_ptr = arr.as_ptr() as *mut c_void; - - let cache = unsafe { randomx_alloc_cache(flag) }; - let size_key = c_key.as_bytes().len() * mem::size_of::<*const c_char>(); - let size_input = c_input.as_bytes().len() * mem::size_of::<*const c_char>(); - let size_input2 = c_input2.as_bytes().len() * mem::size_of::<*const c_char>(); - let size_input3 = c_input3.as_bytes().len() * mem::size_of::<*const c_char>(); - - unsafe { - randomx_init_cache(cache, c_key_ptr, size_key); - } - - let dataset = unsafe { randomx_alloc_dataset(flag) }; - - unsafe { randomx_init_dataset(dataset, cache, 0, (RANDOMX_DATASET_ITEM_SIZE - 1).into()) } - - let vm = unsafe { randomx_create_vm(flag, cache, ptr::null_mut()) }; - - unsafe { - randomx_calculate_hash_first(vm, c_input_ptr, size_input); - } - - let mut vec = Vec::new(); - let mut vec2 = Vec::new(); - let mut vec3 = Vec::new(); - - unsafe { - randomx_calculate_hash_next(vm, c_input_ptr2, size_input2, output_ptr); - } - - for i in 0..RANDOMX_HASH_SIZE { - vec.push(arr[i as usize] as u8); - vec2.push(0u8); - vec3.push(arr[i as usize] as u8); - } - assert_ne!(vec, vec2); //vec2 is filled with 0 - - unsafe { - randomx_calculate_hash_next(vm, c_input_ptr3, size_input3, output_ptr); - } - - for i in 0..RANDOMX_HASH_SIZE { - vec.push(arr[i as usize] as u8); - vec2.push(0u8); - } - assert_ne!(vec, vec2); //vec2 is filled with 0 - assert_ne!(vec, vec3); //vec3 is previous hash - - for i in 0..RANDOMX_HASH_SIZE { - vec3.push(arr[i as usize] as u8); - } - - unsafe { - randomx_calculate_hash_last(vm, output_ptr); - } - - for i in 0..RANDOMX_HASH_SIZE { - vec.push(arr[i as usize] as u8); - vec2.push(0u8); - } - assert_ne!(vec, vec2); //vec2 is filled with 0 - assert_ne!(vec, vec3); //vec3 is previous hash - - unsafe { - randomx_destroy_vm(vm); - randomx_release_cache(cache); - } - } -} diff --git a/rust-randomx/src/lib.rs b/rust-randomx/src/lib.rs deleted file mode 100644 index 20f7141..0000000 --- a/rust-randomx/src/lib.rs +++ /dev/null @@ -1,631 +0,0 @@ -// Copyright 2019. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -//! # randomx-rs -//! -//! The `randomx-rs` crate provides bindings to the `RandomX` proof-of-work (PoW) system as well -//! as the functionality to utilize these bindings. -//! -mod bindings; -#[macro_use] -extern crate bitflags; -extern crate libc; - -use bindings::{ - randomx_alloc_cache, randomx_alloc_dataset, randomx_cache, randomx_calculate_hash, - randomx_create_vm, randomx_dataset, randomx_dataset_item_count, randomx_destroy_vm, - randomx_get_dataset_memory, randomx_init_cache, randomx_init_dataset, randomx_release_cache, - randomx_release_dataset, randomx_vm, randomx_vm_set_cache, randomx_vm_set_dataset, - RANDOMX_DATASET_ITEM_SIZE, RANDOMX_HASH_SIZE, -}; - -use crate::bindings::{ - randomx_calculate_hash_first, randomx_calculate_hash_last, randomx_calculate_hash_next, - randomx_get_flags, -}; -use derive_error::Error; -use libc::{c_ulong, c_void}; -use std::ptr; - -bitflags! { -/// Indicates to the RandomX library which configuration options to use. - pub struct RandomXFlag: u32 { - /// All flags not set, works on all platforms, however is the slowest - const FLAG_DEFAULT =0b0000_0000; - /// Allocate memory in large pages - const FLAG_LARGE_PAGES =0b0000_0001; - /// Use hardware accelerated AES - const FLAG_HARD_AES =0b0000_0010; - /// Use the full dataset - const FLAG_FULL_MEM =0b0000_0100; - /// Use JIT compilation support - const FLAG_JIT =0b0000_1000; - /// When combined with FLAG_JIT, the JIT pages are never writable and executable at the - /// same time - const FLAG_SECURE =0b0001_0000; - /// Optimize Argon2 for CPUs with the SSSE3 instruction set - const FLAG_ARGON2_SSSE3 =0b0010_0000; - /// Optimize Argon2 for CPUs with the AVX2 instruction set - const FLAG_ARGON2_AVX2 =0b0100_0000; - /// Optimize Argon2 for CPUs without the AVX2 or SSSE3 instruction sets - const FLAG_ARGON2 =0b0110_0000; - } -} - -impl RandomXFlag { - /// Returns the recommended flags to be used. - /// - /// Does not include: - /// * FLAG_LARGE_PAGES - /// * FLAG_FULL_MEM - /// * FLAG_SECURE - /// - /// The above flags need to be set manually, if required. - pub fn get_recommended_flags() -> RandomXFlag { - // c code will always return a value - RandomXFlag { - bits: unsafe { randomx_get_flags() }, - } - } -} - -impl Default for RandomXFlag { - /// Default value for RandomXFlag - fn default() -> RandomXFlag { - RandomXFlag::FLAG_DEFAULT - } -} - -#[derive(Debug, Clone, Error)] -/// Custom error enum -pub enum RandomXError { - /// Problem creating the RandomX object - CreationError, - /// Problem with configuration flags - FlagConfigError, - /// Problem with parameters supplied - ParameterError, - /// Problem running RandomX - Other, -} - -#[derive(Debug)] -/// Cache structure -pub struct RandomXCache { - cache: *mut randomx_cache, -} - -impl Drop for RandomXCache { - /// De-allocates memory for the `cache` object - fn drop(&mut self) { - unsafe { - randomx_release_cache(self.cache); - } - } -} - -impl RandomXCache { - /// Creates a new cache object, allocates memory to the `cache` object and initializes it with - /// he key value, error on failure. - /// - /// `flags` is any combination of the following two flags: - /// * FLAG_LARGE_PAGES - /// * FLAG_JIT - /// - /// and (optionally) one of the following flags (depending on instruction set supported): - /// * FLAG_ARGON2_SSSE3 - /// * FLAG_ARGON2_AVX2 - /// - /// `key` is a sequence of u8 used to initialize SuperScalarHash. - pub fn new(flags: RandomXFlag, key: &[u8]) -> Result { - if key.is_empty() { - return Err(RandomXError::ParameterError); - }; - let test = unsafe { randomx_alloc_cache(flags.bits) }; - if test.is_null() { - Err(RandomXError::CreationError) - } else { - let result = RandomXCache { cache: test }; - let key_ptr = key.as_ptr() as *mut c_void; - let key_size = key.len() as usize; - unsafe { - //no way to check if this fails, c code does not return anything - randomx_init_cache(result.cache, key_ptr, key_size); - } - Ok(result) - } - } -} - -#[derive(Debug)] -/// Dataset structure -pub struct RandomXDataset { - dataset: *mut randomx_dataset, - dataset_start: c_ulong, - dataset_count: c_ulong, -} - -impl Drop for RandomXDataset { - /// De-allocates memory for the `dataset` object. - fn drop(&mut self) { - unsafe { - randomx_release_dataset(self.dataset); - } - } -} - -impl RandomXDataset { - /// Creates a new dataset object, allocates memory to the `dataset` object and initializes it, - /// error on failure. - /// - /// `flags` is one of the following: - /// * FLAG_DEFAULT - /// * FLAG_LARGE_PAGES - /// - /// `cache` is a cache object. - /// - /// `start` is the item number where initialization should start, recommended to pass in 0. - pub fn new( - flags: RandomXFlag, - cache: &RandomXCache, - start: c_ulong, - ) -> Result { - // let count = c_ulong::from(RANDOMX_DATASET_ITEM_SIZE - 1) - start; - let count: c_ulong = unsafe { randomx_dataset_item_count() } as u64; - let test = unsafe { randomx_alloc_dataset(flags.bits) }; - if test.is_null() { - Err(RandomXError::CreationError) - } else { - let result = RandomXDataset { - dataset: test, - dataset_start: start, - dataset_count: count, - }; - let item_count = match result.count() { - Ok(v) => v, - Err(_) => return Err(RandomXError::CreationError), - }; - // Mirror the assert checks inside randomx_init_dataset call - if !((start < (item_count as c_ulong) && count <= (item_count as c_ulong)) - || (start + (item_count as c_ulong) <= count)) - { - return Err(RandomXError::CreationError); - } - - unsafe { - //no way to check if this fails, c code does not return anything - randomx_init_dataset( - result.dataset, - cache.cache, - start as c_ulong, - count as c_ulong, - ); - } - Ok(result) - } - } - - /// Returns the number of items in the `dataset` or an error on failure. - pub fn count(&self) -> Result { - match unsafe { randomx_dataset_item_count() } { - 0 => Err(RandomXError::Other), - x => Ok(x as u64), - } - } - - /// Returns the values of the internal memory buffer of the `dataset` or an error on failure. - pub fn get_data(&self) -> Result, RandomXError> { - let memory = unsafe { randomx_get_dataset_memory(self.dataset) }; - if memory.is_null() { - return Err(RandomXError::Other); - } - let mut result: Vec = vec![0u8; self.dataset_count as usize]; - unsafe { - libc::memcpy( - result.as_mut_ptr() as *mut c_void, - memory, - self.dataset_count as usize, - ); - } - Ok(result) - } -} - -#[derive(Debug)] -/// VM structure -pub struct RandomXVM { - flags: RandomXFlag, - vm: *mut randomx_vm, -} - -impl Drop for RandomXVM { - /// De-allocates memory for the `VM` object. - fn drop(&mut self) { - unsafe { - randomx_destroy_vm(self.vm); - } - } -} - -impl RandomXVM { - /// Creates a new `VM` and initializes it, error on failure. - /// - /// `flags` is any combination of the following 5 flags: - /// * FLAG_LARGE_PAGES - /// * FLAG_HARD_AES - /// * FLAG_FULL_MEM - /// * FLAG_JIT - /// * FLAG_SECURE - /// - /// Or - /// - /// * FLAG_DEFAULT - /// - /// `cache` is a cache object, optional if FLAG_FULL_MEM is set. - /// - /// `dataset` is a dataset object, optional if FLAG_FULL_MEM is not set. - pub fn new( - flags: RandomXFlag, - cache: Option<&RandomXCache>, - dataset: Option<&RandomXDataset>, - ) -> Result { - let test: *mut randomx_vm; - let mut is_full_mem = false; - let flag_full_mem = RandomXFlag::FLAG_FULL_MEM; - - // intersection of flags - if flags & flag_full_mem == flag_full_mem { - is_full_mem = true; - } - - if cache.is_none() && !is_full_mem { - return Err(RandomXError::FlagConfigError); - } - - if dataset.is_none() && is_full_mem { - return Err(RandomXError::FlagConfigError); - } - - match cache { - Some(stash) => match dataset { - Some(data) => unsafe { - test = randomx_create_vm(flags.bits, stash.cache, data.dataset) - }, - None => unsafe { - test = randomx_create_vm(flags.bits, stash.cache, ptr::null_mut()) - }, - }, - None => match dataset { - Some(data) => unsafe { - test = randomx_create_vm(flags.bits, ptr::null_mut(), data.dataset) - }, - None => test = ptr::null_mut(), - }, - } - - if test.is_null() { - return Err(RandomXError::CreationError); - } - - let result = RandomXVM { vm: test, flags }; - Ok(result) - } - - /// Re-initializes the `VM` with a new cache that was initialised without - /// RandomXFlag::FLAG_FULL_MEM. - pub fn reinit_cache(&self, cache: &RandomXCache) -> Result<(), RandomXError> { - if self.flags & RandomXFlag::FLAG_FULL_MEM == RandomXFlag::FLAG_FULL_MEM { - return Err(RandomXError::FlagConfigError); - } - //no way to check if this fails, c code does not return anything - unsafe { - randomx_vm_set_cache(self.vm, cache.cache); - } - Ok(()) - } - - /// Re-initializes the `VM` with a new dataset that was initialised with - /// RandomXFlag::FLAG_FULL_MEM. - pub fn reinit_dataset(&self, dataset: &RandomXDataset) -> Result<(), RandomXError> { - if self.flags & RandomXFlag::FLAG_FULL_MEM != RandomXFlag::FLAG_FULL_MEM { - return Err(RandomXError::FlagConfigError); - } - //no way to check if this fails, c code does not return anything - unsafe { - randomx_vm_set_dataset(self.vm, dataset.dataset); - } - Ok(()) - } - - /// Calculates a RandomX hash value and returns it, error on failure. - /// - /// `input` is a sequence of u8 to be hashed. - pub fn calculate_hash(&self, input: &[u8]) -> Result<[u8; 32], RandomXError> { - if input.is_empty() { - return Err(RandomXError::ParameterError); - }; - let size_input = input.len() as usize; - let input_ptr = input.as_ptr() as *mut c_void; - let arr = [0; RANDOMX_HASH_SIZE as usize]; - let output_ptr = arr.as_ptr() as *mut c_void; - unsafe { - randomx_calculate_hash(self.vm, input_ptr, size_input, output_ptr); - } - // if this failed, arr should still be empty - if arr == [0; RANDOMX_HASH_SIZE as usize] { - return Err(RandomXError::Other); - } - let result = arr; - Ok(result) - } - - /// Calculates hashes from a set of inputs. - /// - /// `input` is an array of a sequence of u8 to be hashed. - #[allow(clippy::needless_range_loop)] // Range loop is not only for indexing `input` - pub fn calculate_hash_set(&self, input: &[&[u8]]) -> Result, RandomXError> { - if input.is_empty() { - // Empty set - return Err(RandomXError::ParameterError); - } - - let mut result = Vec::new(); - // For single input - if input.len() == 1 { - let hash_result = self.calculate_hash(input[0]); - return match hash_result { - Ok(hash) => { - result.push(hash); - Ok(result) - } - Err(e) => Err(e), - }; - } - - // For multiple inputs - let mut output_ptr: *mut c_void = ptr::null_mut(); - let arr = [0; RANDOMX_HASH_SIZE as usize]; - - // Not len() as last iteration assigns final hash - let iterations = input.len() + 1; - for i in 0..iterations { - if i != iterations - 1 { - if input[i].is_empty() { - // Stop calculations - if arr != [0; RANDOMX_HASH_SIZE as usize] { - // Complete what was started - unsafe { - randomx_calculate_hash_last(self.vm, output_ptr); - } - } - return Err(RandomXError::ParameterError); - }; - let size_input = input[i].len() as usize; - let input_ptr = input[i].as_ptr() as *mut c_void; - output_ptr = arr.as_ptr() as *mut c_void; - if i == 0 { - // For first iteration - unsafe { - randomx_calculate_hash_first(self.vm, input_ptr, size_input); - } - } else { - unsafe { - // For every other iteration - randomx_calculate_hash_next(self.vm, input_ptr, size_input, output_ptr); - } - } - } else { - // For last iteration - unsafe { - randomx_calculate_hash_last(self.vm, output_ptr); - } - } - - if i != 0 { - // First hash is only available in 2nd iteration - if arr == [0; RANDOMX_HASH_SIZE as usize] { - return Err(RandomXError::Other); - } - let output: Vec = arr.to_vec(); - result.push([0; 32]); - } - } - Ok(result) - } -} - -#[cfg(test)] -mod tests { - use crate::{RandomXCache, RandomXDataset, RandomXFlag, RandomXVM}; - - #[test] - fn lib_alloc_cache() { - let flags = RandomXFlag::default(); - let key = "Key"; - let cache = RandomXCache::new(flags, key.as_bytes()); - if let Err(i) = cache { - panic!(format!("Failed to allocate cache, {}", i)); - } - drop(cache); - } - - #[test] - fn lib_alloc_dataset() { - let flags = RandomXFlag::default(); - let key = "Key"; - let cache = RandomXCache::new(flags, key.as_bytes()).unwrap(); - let dataset = RandomXDataset::new(flags, &cache, 0); - if let Err(i) = dataset { - panic!(format!("Failed to allocate dataset, {}", i)); - } - drop(dataset); - drop(cache); - } - - #[test] - fn lib_alloc_vm() { - let flags = RandomXFlag::default(); - let key = "Key"; - let cache = RandomXCache::new(flags, key.as_bytes()).unwrap(); - let mut vm = RandomXVM::new(flags, Some(&cache), None); - if let Err(i) = vm { - panic!(format!("Failed to allocate vm, {}", i)); - } - drop(vm); - let dataset = RandomXDataset::new(flags, &cache, 0).unwrap(); - vm = RandomXVM::new(flags, Some(&cache), Some(&dataset)); - if let Err(i) = vm { - panic!(format!("Failed to allocate vm, {}", i)); - } - drop(dataset); - drop(cache); - drop(vm); - } - - #[test] - fn lib_dataset_memory() { - let flags = RandomXFlag::default(); - let key = "Key"; - let cache = RandomXCache::new(flags, key.as_bytes()).unwrap(); - let dataset = RandomXDataset::new(flags, &cache, 0).unwrap(); - let memory = dataset.get_data().unwrap_or(std::vec::Vec::new()); - if memory.len() == 0 { - panic!("Failed to get dataset memory"); - } - let vec = vec![0u8; memory.len() as usize]; - assert_ne!(memory, vec); - drop(dataset); - drop(cache); - } - - #[test] - fn lib_calculate_hash() { - let flags = RandomXFlag::get_recommended_flags(); - let flags2 = flags | RandomXFlag::FLAG_FULL_MEM; - let key = "Key"; - let input = "Input"; - let cache1 = RandomXCache::new(flags, key.as_bytes()).unwrap(); - let vm1 = RandomXVM::new(flags, Some(&cache1), None).unwrap(); - let hash1 = vm1.calculate_hash(input.as_bytes()).expect("no data"); - let vec = vec![0u8; hash1.len() as usize]; - assert_ne!(hash1, vec); - let reinit_cache = vm1.reinit_cache(&cache1); - assert_eq!(reinit_cache.is_ok(), true); - let hash2 = vm1.calculate_hash(input.as_bytes()).expect("no data"); - assert_ne!(hash2, vec); - assert_eq!(hash1, hash2); - - let cache2 = RandomXCache::new(flags, key.as_bytes()).unwrap(); - let vm2 = RandomXVM::new(flags, Some(&cache2), None).unwrap(); - let hash3 = vm2.calculate_hash(input.as_bytes()).expect("no data"); - assert_eq!(hash2, hash3); - - let cache3 = RandomXCache::new(flags, key.as_bytes()).unwrap(); - let dataset3 = RandomXDataset::new(flags, &cache3, 0).unwrap(); - let vm3 = RandomXVM::new(flags2, None, Some(&dataset3)).unwrap(); - let hash4 = vm3.calculate_hash(input.as_bytes()).expect("no data"); - assert_ne!(hash3, vec); - let reinit_dataset = vm3.reinit_dataset(&dataset3); - assert_eq!(reinit_dataset.is_ok(), true); - let hash5 = vm3.calculate_hash(input.as_bytes()).expect("no data"); - assert_ne!(hash4, vec); - assert_eq!(hash4, hash5); - - let cache4 = RandomXCache::new(flags, key.as_bytes()).unwrap(); - let dataset4 = RandomXDataset::new(flags, &cache4, 0).unwrap(); - let vm4 = RandomXVM::new(flags2, Some(&cache4), Some(&dataset4)).unwrap(); - let hash6 = vm3.calculate_hash(input.as_bytes()).expect("no data"); - assert_eq!(hash5, hash6); - - drop(dataset3); - drop(dataset4); - drop(cache1); - drop(cache2); - drop(cache3); - drop(vm1); - drop(vm2); - drop(vm3); - drop(vm4); - } - - #[test] - fn lib_calculate_hash_set() { - let flags = RandomXFlag::default(); - let key = "Key"; - let mut inputs = Vec::new(); - inputs.push("Input".as_bytes()); - inputs.push("Input 2".as_bytes()); - inputs.push("Inputs 3".as_bytes()); - let cache = RandomXCache::new(flags, key.as_bytes()).unwrap(); - let vm = RandomXVM::new(flags, Some(&cache), None).unwrap(); - let hashes = vm.calculate_hash_set(inputs.as_slice()).expect("no data"); - assert_eq!(inputs.len(), hashes.len()); - let mut prev_hash = Vec::new(); - let mut i = 0; - for hash in hashes { - let vec = vec![0u8; hash.len() as usize]; - assert_ne!(hash, vec); - assert_ne!(hash, prev_hash); - let compare = vm.calculate_hash(inputs[i]).unwrap(); //sanity check - assert_eq!(hash, compare); - prev_hash = hash; - i += 1; - } - drop(cache); - drop(vm); - } - - #[test] - fn lib_calculate_hash_is_consistent() { - let flags = RandomXFlag::get_recommended_flags(); - let key = "Key"; - let input = "Input"; - let cache = RandomXCache::new(flags, key.as_bytes()).unwrap(); - let dataset = RandomXDataset::new(flags, &cache, 0).unwrap(); - let vm = RandomXVM::new(flags, Some(&cache), Some(&dataset)).unwrap(); - let hash = vm.calculate_hash(input.as_bytes()).expect("no data"); - assert_eq!( - hash, - [ - 114, 81, 192, 5, 165, 242, 107, 100, 184, 77, 37, 129, 52, 203, 217, 227, 65, 83, - 215, 213, 59, 71, 32, 172, 253, 155, 204, 111, 183, 213, 157, 155 - ] - ); - drop(vm); - drop(dataset); - drop(cache); - - let cache1 = RandomXCache::new(flags, key.as_bytes()).unwrap(); - let dataset1 = RandomXDataset::new(flags, &cache1, 0).unwrap(); - let vm1 = RandomXVM::new(flags, Some(&cache1), Some(&dataset1)).unwrap(); - let hash1 = vm1.calculate_hash(input.as_bytes()).expect("no data"); - assert_eq!( - hash1, - [ - 114, 81, 192, 5, 165, 242, 107, 100, 184, 77, 37, 129, 52, 203, 217, 227, 65, 83, - 215, 213, 59, 71, 32, 172, 253, 155, 204, 111, 183, 213, 157, 155 - ] - ); - drop(vm1); - drop(dataset1); - drop(cache1); - } -} diff --git a/rust-randomx/test b/rust-randomx/test deleted file mode 100644 index e69de29..0000000 diff --git a/src/block.rs b/src/block.rs index b51f2e3..cc1b546 100644 --- a/src/block.rs +++ b/src/block.rs @@ -1,73 +1,83 @@ use std::vec; -use serde::Deserialize as TraitDeserialize; -use serde_derive::{Serialize,Deserialize}; -use crate::hexbytes; -#[derive(Debug,Deserialize,Serialize)] +use serde_derive::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] pub struct Block { - pub id:Option, - pub jsonrpc:String, - pub error:Option, - pub result:BlockResult, + pub id: Option, + pub jsonrpc: String, + pub error: Option, + pub result: BlockResult, } -#[derive(Debug,Deserialize,Serialize,Clone)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct JobBlock { - pub jsonrpc:String, - pub error:Option, - pub params:JobBlockResult, + pub jsonrpc: String, + pub error: Option, + pub params: JobBlockResult, + pub timestamp: u64, } -#[derive(Debug,Deserialize,Serialize,Clone)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct JobBlockResult { - pub blob:String, - pub job_id:String, - pub target:String, - pub id:String, + pub blob: String, + pub job_id: String, + pub target: String, + pub id: String, pub timestamp:u64, - pub height:u32, - pub algo:String, + pub height: u32, + pub algo: String, pub variant:String, - pub seed_hash:String + pub seed_hash: String, } impl JobBlock { pub fn to_block(self) -> Block { - Block { id: None, jsonrpc: self.jsonrpc, error: self.error, result: self.params.to_block_res() } + Block { + id: None, + jsonrpc: self.jsonrpc, + error: self.error, + result: self.params.to_block_res(), + } } } impl JobBlockResult { pub fn to_block_res(self) -> BlockResult { let job = Job { - blob:self.blob, - job_id:self.job_id, - target:self.target, - id:self.id, + blob: self.blob, + job_id: self.job_id, + target: self.target, + id: self.id, timestamp:self.timestamp, - algo:self.algo, - height:self.height as u64, + algo: self.algo, + height: self.height as u64, motd:String::new(), - seed_hash:self.seed_hash, + seed_hash: self.seed_hash, variant:self.variant }; - BlockResult { id:None , job, extensions: vec![], status: String::new() } + BlockResult { + id: None, + job, + extensions: vec![], + status: String::new(), + } } } -#[derive(Debug,Deserialize,Serialize,Clone)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct BlockResult { - pub id:Option, - pub job:Job, - pub extensions:Vec, - pub status:String, + pub id: Option, + pub job: Job, + pub extensions: Vec, + pub status: String, } -#[derive(Debug,Deserialize,Serialize,Clone)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct Job { - pub blob:String, - pub job_id:String, - pub target:String, - pub id:String, + pub blob: String, + pub job_id: String, + pub target: String, + pub id: String, pub timestamp:u64, - pub height:u64, - pub algo:String, + pub height: u64, + pub algo: String, pub variant:String, - pub seed_hash:String, + pub seed_hash: String, pub motd:String, } diff --git a/src/hashing.rs b/src/hashing.rs index e69de29..8b13789 100644 --- a/src/hashing.rs +++ b/src/hashing.rs @@ -0,0 +1 @@ + diff --git a/src/hexbytes.rs b/src/hexbytes.rs index d33edeb..19420bd 100644 --- a/src/hexbytes.rs +++ b/src/hexbytes.rs @@ -1,14 +1,14 @@ +use byteorder::{ByteOrder, LE}; use hex::FromHex; -use byteorder::{LE,ByteOrder}; use std::str; /// Deserialize a value of up to 64 bits, reporting number of hex bytes it contained -pub fn pack_nonce(blob:&mut [u8],nonce:&[u8;4]) { +pub fn pack_nonce(blob: &mut [u8], nonce: &[u8; 4]) { blob[39] = nonce[0]; blob[40] = nonce[1]; blob[41] = nonce[2]; blob[42] = nonce[3]; } -pub fn target_to_u64(hex:&str) -> u64 { +pub fn target_to_u64(hex: &str) -> u64 { let diff = LE::read_u32(hex.as_bytes()); u64::MAX / ((u32::MAX as u64) / diff as u64) } @@ -34,10 +34,9 @@ pub fn nonce_hex(nonce: u32) -> String { pub fn with_nonce(blob: &str, nonce: &str) -> String { let (a, _) = blob.split_at(78); let (_, b) = blob.split_at(86); - return format!("{}{}{}", a, nonce, b); + format!("{}{}{}", a, nonce, b) } - pub fn job_target_value(hex_str: &str) -> u64 { let t = hex2_u32_le(hex_str); u64::max_value() / (u64::from(u32::max_value()) / u64::from(t)) @@ -55,7 +54,7 @@ pub fn hex2_u32_le(hex: &str) -> u32 { pub fn hash_target_value(hex_str: &str) -> u64 { hex2_u64_le(&hex_str[48..]) } -pub fn bytes_to_hex(bytes:&[u8]) -> String { +pub fn bytes_to_hex(bytes: &[u8]) -> String { let mut s = String::new(); let table = b"0123456789abcdef"; for &b in bytes { @@ -90,4 +89,3 @@ pub fn string_to_u8_array(hex: &str) -> Vec { } bytes } - diff --git a/src/login.json b/src/login.json deleted file mode 100644 index 1153ecf..0000000 --- a/src/login.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "access-log-file": null, - "access-password": null, - "algo-ext": true, - "api": { - "id": null, - "worker-id": null - }, - "http": { - "enabled": false, - "host": "127.0.0.1", - "port": 0, - "access-token": null, - "restricted": true - }, - "background": false, - "bind": [ - { - "host": "0.0.0.0", - "port": 3333, - "tls": false - }, - { - "host": "::", - "port": 3333, - "tls": false - } - ], - "colors": true, - "custom-diff": 0, - "donate-level": 1, - "log-file": null, - "mode": "nicehash", - "pools": [ - { - "algo": null, - "url": "pool.hashvault.pro:80", - "user": "49sygkbkGRYgBRywwhovJp75gUFPwqqepfLyCuaVv4VbAVRSdtRd1ggMbZdzVRnQF3EVhcu2Ekz9n3YepBtFSJbW17U7h1z", - "pass": "rustyyminnerrfklds", - "rig-id": null, - "keepalive": false, - "enabled": true, - "tls": true, - "tls-fingerprint": "420c7850e09b7c0bdcf748a7da9eb3647daf8515718f36d9ccfdd6b9ff834b14", - "daemon": false - } - ], - "retries": 2, - "retry-pause": 1, - "reuse-timeout": 0, - "tls": { - "protocols": null, - "cert": null, - "cert_key": null, - "ciphers": null, - "ciphersuites": null, - "dhparam": null - }, - "user-agent": null, - "syslog": false, - "verbose": false, - "watch": true, - "workers": true -} diff --git a/src/main.rs b/src/main.rs index f873732..cdb1205 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,40 +1,53 @@ -use tokio::sync::mpsc; -use randomx::memory::VmMemory; -use randomx::vm::new_vm; use std::{ - sync::{Arc,Mutex}, + io::{self, BufRead, BufReader}, + sync::{Arc, Mutex}, time::Duration, - io::{self,BufRead, BufReader}, }; +use tokio::sync::mpsc; + +const POOLADDR: &str = "pool.hashvault.pro:80"; //POOL ADDRESS +const WALLET: &str = "49sygkbkGRYgBRywwhovJp75gUFPwqqepfLyCuaVv4VbAVRSdtRd1ggMbZdzVRnQF3EVhcu2Ekz9n3YepBtFSJbW17U7h1z"; //WALLET ADDRESS +const THREADS: u16 = 4; //Number of threads of your CPU +const LIGHTMODE: bool = false; -const POOLADDR:&str = "pool.hashvault.pro:80"; -const WALLET:&str = "49sygkbkGRYgBRywwhovJp75gUFPwqqepfLyCuaVv4VbAVRSdtRd1ggMbZdzVRnQF3EVhcu2Ekz9n3YepBtFSJbW17U7h1z"; -const THREADS:usize = 4; -const LIGHTMODE:bool = false; mod block; -mod request; +mod hashing; mod hexbytes; +mod miner; mod randomx; +mod request; mod tcp; -mod hashing; -mod miner; fn main() { - let login = request::Login { - login:WALLET.to_string(), - pass: "rustyminer".to_string(), - agent:"pow#er/0.2.0".to_string(), + avx2() //unsafe {avx2()} +} + +pub fn keep_alive(stream: Arc>, id: &str) { + let keep_alive: request::KeepAlive = request::KeepAlive { id: id.to_string() }; + stream + .send(request::MessageType::KeepAlive(keep_alive)) + .unwrap(); +} + +//#[target_feature(enable = "avx2")] +//AVX2 is off +fn avx2() { + let login: request::Login = request::Login { + login: WALLET.to_string(), + pass: "nobaki".to_string(), + agent: "pow#er/0.2.0".to_string(), }; - let request = request::Request { - method:"login".to_string(), - params:&login, - id:1, + let request: request::Request<'_, request::Login> = request::Request { + method: "login".to_string(), + params: &login, + id: 1, }; - let stream = tcp::connect(POOLADDR, request).unwrap(); - let mut stream_r = BufReader::with_capacity(1500, stream.try_clone().unwrap()); - let mut buffer = String::new(); + let stream: std::net::TcpStream = tcp::connect(POOLADDR, request.clone()).unwrap(); + let mut stream_r: BufReader = + BufReader::with_capacity(1500, stream.try_clone().unwrap()); + let mut buffer: String = String::new(); loop { match stream_r.read_line(&mut buffer) { Ok(_o) => { @@ -43,52 +56,54 @@ fn main() { continue; } break; - }, - Err(err) if (err.kind() == io::ErrorKind::WouldBlock) | (err.kind() == io::ErrorKind::TimedOut) => { + } + Err(err) + if (err.kind() == io::ErrorKind::WouldBlock) + | (err.kind() == io::ErrorKind::TimedOut) => + { println!("no data found"); continue; - }, + } Err(err) => { panic!("{err:?}"); } } } println!("{buffer}"); - let block = serde_json::from_str::(&buffer).unwrap(); - let mut threads = vec![]; - let (send,reciever) = mpsc::unbounded_channel(); - let send = Arc::new(send); - let mut client = tcp::Client { stream, reciever }; - let (sender,recv) = mpsc::unbounded_channel(); - let recv = Arc::new(Mutex::new(recv)); + let block: block::Block = serde_json::from_str::(&buffer).unwrap(); + let mut threads: Vec> = vec![]; + let (send, reciever) = mpsc::unbounded_channel(); + let send: Arc> = Arc::new(send); + let mut client: tcp::Client = tcp::Client { stream, reciever }; + let (sender, recv) = mpsc::unbounded_channel(); + let recv: Arc)>>> = + Arc::new(Mutex::new(recv)); for i in 1..=THREADS { - let block = block.result.clone(); - let r = Arc::clone(&recv); - let s = Arc::clone(&send); - let miner = std::thread::spawn(move || { - println!("skip on {i}"); - miner::mine_monero(block,s,r,i as u32,THREADS as u32); + let block: block::BlockResult = block.result.clone(); + let r: Arc)>>> = + Arc::clone(&recv); + let s: Arc> = Arc::clone(&send); + let miner: std::thread::JoinHandle<()> = std::thread::spawn(move || { + println!("skip on {i} thread"); + miner::mine_rx(block, s, r, i as u32, THREADS as u32); }); threads.push(miner); } - let id = block.result.id.unwrap(); + let id: String = block.result.id.unwrap(); std::thread::spawn(move || { - let stream = Arc::clone(&send); + let stream: Arc> = Arc::clone(&send); loop { keep_alive(Arc::clone(&stream), &id); std::thread::sleep(Duration::from_secs(15)); } }); - std::thread::spawn(move || { client.message_listener() }); + std::thread::spawn(move || client.message_listener()); - std::thread::spawn(move || { + std::thread::spawn(move || { request::job_listener(stream_r, sender); }); - for i in threads { i.join().unwrap(); } -} - -pub fn keep_alive(stream:Arc>,id:&str) { - let keep_alive = request::KeepAlive { id:id.to_string() }; - stream.send(request::MessageType::KeepAlive(keep_alive)).unwrap(); + for i in threads { + i.join().unwrap(); + } } diff --git a/src/miner.rs b/src/miner.rs index 85ca94e..b88b1c6 100644 --- a/src/miner.rs +++ b/src/miner.rs @@ -1,39 +1,65 @@ -use tokio::sync::mpsc; use crate::randomx::memory::VmMemory; use crate::randomx::vm::new_vm; -use crate::{block,request,hexbytes}; -use std::sync::{Arc,Mutex}; +use crate::{block, hexbytes, request, LIGHTMODE}; +use std::sync::{Arc, Mutex}; +use stopwatch::Stopwatch; +use tokio::sync::mpsc; + +pub fn mine_rx( + mut block: block::BlockResult, + sender: Arc>, + recv: Arc)>>>, + start: u32, + skip: u32, +) { + let mut num_target: u64 = hexbytes::job_target_value(&block.job.target); + println!("Difficulty: {}", num_target); + let mut nonce: u32 = start; -pub fn mine_monero( - mut block:block::BlockResult, - sender:Arc>, - recv:Arc)>>>, - start:u32, - skip:u32 - ) { - let mut num_target = hexbytes::job_target_value(&block.job.target); - println!("{num_target}"); - let mut nonce = start; + let mut last: i64 = 0; + let cycles_const: u8 = 10; + let mut cycles: u8 = 0; + let mut hashes: f64 = 0.0; - let seed = hexbytes::string_to_u8_array(&block.job.seed_hash); - let memory = VmMemory::light(&seed); - let mut vm = new_vm(memory.into()); + let seed: Vec = hexbytes::string_to_u8_array(&block.job.seed_hash); + let memory: VmMemory = if LIGHTMODE { + VmMemory::full(&seed) + } else { + VmMemory::light(&seed) + }; + let mut vm: crate::randomx::vm::Vm = new_vm(memory.into()); + let mut sw: Stopwatch = Stopwatch::start_new(); loop { - let nonce_hex = hexbytes::nonce_hex(nonce); - let hash_in = hexbytes::with_nonce(&block.job.blob, &nonce_hex); - let bytes_in = hexbytes::string_to_u8_array(&hash_in); + let nonce_hex: String = hexbytes::nonce_hex(nonce); + let hash_in: String = hexbytes::with_nonce(&block.job.blob, &nonce_hex); + let bytes_in: Vec = hexbytes::string_to_u8_array(&hash_in); + + let hash_result: arrayvec::ArrayString<128> = vm.calculate_hash(&bytes_in).to_hex(); + let hash_val: u64 = hexbytes::hash_target_value(&hash_result); + //println!("Nonce: {nonce} from {start} thread"); + if last > 0 && cycles == cycles_const { + println!( + "{} H/s from {start} thread", + hashes / ((sw.elapsed_ms() - last) as f64 * 0.001) + ); //from XMRig code + sw.restart(); + cycles = 0; + hashes = 0.0; + } + + last = sw.elapsed_ms(); + cycles += 1; + hashes += 1.0; - let hash_result = vm.calculate_hash(&bytes_in).to_hex(); - let hash_val = hexbytes::hash_target_value(&hash_result); - println!("{nonce}"); if hash_val <= num_target { + //< println!("found share"); - let share = request::Share { - id:block.job.id.clone(), - job_id:block.job.job_id.clone(), - nonce:nonce_hex, - result:hash_result.to_string() + let share: request::Share = request::Share { + id: block.job.id.clone(), + job_id: block.job.job_id.clone(), + nonce: nonce_hex, + result: hash_result.to_string(), }; sender.send(request::MessageType::Submit(share)).unwrap(); println!("sent share"); diff --git a/src/randomx/hash.rs b/src/randomx/hash.rs index 6033c79..f0a0399 100644 --- a/src/randomx/hash.rs +++ b/src/randomx/hash.rs @@ -1,6 +1,7 @@ use super::m128::m128i; #[allow(overflowing_literals)] +//#[target_feature(enable = "avx2")] fn keys_1rx4() -> (m128i, m128i, m128i, m128i) { ( m128i::from_i32(0xb4f44917, 0xdbb5552b, 0x62716609, 0x6daca553), @@ -11,20 +12,21 @@ fn keys_1rx4() -> (m128i, m128i, m128i, m128i) { } #[allow(overflowing_literals)] +//#[target_feature(enable = "avx2")] pub fn hash_aes_1rx4(input: &[u64]) -> [m128i; 4] { debug_assert!(input.len() % 64 == 0); - let mut state0 = m128i::from_i32(0xd7983aad, 0xcc82db47, 0x9fa856de, 0x92b52c0d); - let mut state1 = m128i::from_i32(0xace78057, 0xf59e125a, 0x15c7b798, 0x338d996e); - let mut state2 = m128i::from_i32(0xe8a07ce4, 0x5079506b, 0xae62c7d0, 0x6a770017); - let mut state3 = m128i::from_i32(0x7e994948, 0x79a10005, 0x07ad828d, 0x630a240c); + let mut state0: m128i = m128i::from_i32(0xd7983aad, 0xcc82db47, 0x9fa856de, 0x92b52c0d); + let mut state1: m128i = m128i::from_i32(0xace78057, 0xf59e125a, 0x15c7b798, 0x338d996e); + let mut state2: m128i = m128i::from_i32(0xe8a07ce4, 0x5079506b, 0xae62c7d0, 0x6a770017); + let mut state3: m128i = m128i::from_i32(0x7e994948, 0x79a10005, 0x07ad828d, 0x630a240c); - let mut i = 0; + let mut i: usize = 0; while i < input.len() { - let in0 = m128i::from_u64(input[i + 1], input[i]); - let in1 = m128i::from_u64(input[i + 3], input[i + 2]); - let in2 = m128i::from_u64(input[i + 5], input[i + 4]); - let in3 = m128i::from_u64(input[i + 7], input[i + 6]); + let in0: m128i = m128i::from_u64(input[i + 1], input[i]); + let in1: m128i = m128i::from_u64(input[i + 3], input[i + 2]); + let in2: m128i = m128i::from_u64(input[i + 5], input[i + 4]); + let in3: m128i = m128i::from_u64(input[i + 7], input[i + 6]); state0 = state0.aesenc(in0); state1 = state1.aesdec(in1); @@ -34,8 +36,8 @@ pub fn hash_aes_1rx4(input: &[u64]) -> [m128i; 4] { i += 8; } - let x_key_0 = m128i::from_i32(0x06890201, 0x90dc56bf, 0x8b24949f, 0xf6fa8389); - let x_key_1 = m128i::from_i32(0xed18f99b, 0xee1043c6, 0x51f4e03c, 0x61b263d1); + let x_key_0: m128i = m128i::from_i32(0x06890201, 0x90dc56bf, 0x8b24949f, 0xf6fa8389); + let x_key_1: m128i = m128i::from_i32(0xed18f99b, 0xee1043c6, 0x51f4e03c, 0x61b263d1); state0 = state0.aesenc(x_key_0); state1 = state1.aesdec(x_key_0); @@ -50,14 +52,15 @@ pub fn hash_aes_1rx4(input: &[u64]) -> [m128i; 4] { [state0, state1, state2, state3] } +//#[target_feature(enable = "avx2")] pub fn fill_aes_1rx4_u64(input: &[m128i; 4], into: &mut Vec) -> [m128i; 4] { let (key0, key1, key2, key3) = keys_1rx4(); - let mut state0 = input[0]; - let mut state1 = input[1]; - let mut state2 = input[2]; - let mut state3 = input[3]; + let mut state0: m128i = input[0]; + let mut state1: m128i = input[1]; + let mut state2: m128i = input[2]; + let mut state3: m128i = input[3]; - let mut out_ix = 0; + let mut out_ix: usize = 0; while out_ix < into.len() { state0 = state0.aesdec(key0); state1 = state1.aesenc(key1); @@ -81,7 +84,8 @@ pub fn fill_aes_1rx4_u64(input: &[m128i; 4], into: &mut Vec) -> [m128i; 4] [state0, state1, state2, state3] } -fn fill_aes_1rx4_m128i(input: &[m128i; 4], into: &mut Vec) -> [m128i; 4] { +#[target_feature(enable = "avx2")] +unsafe fn fill_aes_1rx4_m128i(input: &[m128i; 4], into: &mut Vec) -> [m128i; 4] { let (key0, key1, key2, key3) = keys_1rx4(); let mut state0 = input[0]; let mut state1 = input[1]; @@ -103,7 +107,11 @@ fn fill_aes_1rx4_m128i(input: &[m128i; 4], into: &mut Vec) -> [m128i; 4] [state0, state1, state2, state3] } -pub fn gen_program_aes_1rx4(input: &[m128i; 4], output_size: usize) -> (Vec, [m128i; 4]) { +#[target_feature(enable = "avx2")] +pub unsafe fn gen_program_aes_1rx4( + input: &[m128i; 4], + output_size: usize, +) -> (Vec, [m128i; 4]) { debug_assert!(output_size % 4 == 0); let mut result: Vec = vec![m128i::zero(); output_size]; @@ -112,24 +120,25 @@ pub fn gen_program_aes_1rx4(input: &[m128i; 4], output_size: usize) -> (Vec Vec { - debug_assert!(output_size % 4 == 0); - let mut result = Vec::with_capacity(output_size); - let key0 = m128i::from_i32(0x99e5d23f, 0x2f546d2b, 0xd1833ddb, 0x6421aadd); - let key1 = m128i::from_i32(0xa5dfcde5, 0x06f79d53, 0xb6913f55, 0xb20e3450); - let key2 = m128i::from_i32(0x171c02bf, 0x0aa4679f, 0x515e7baf, 0x5c3ed904); - let key3 = m128i::from_i32(0xd8ded291, 0xcd673785, 0xe78f5d08, 0x85623763); - let key4 = m128i::from_i32(0x229effb4, 0x3d518b6d, 0xe3d6a7a6, 0xb5826f73); - let key5 = m128i::from_i32(0xb272b7d2, 0xe9024d4e, 0x9c10b3d9, 0xc7566bf3); - let key6 = m128i::from_i32(0xf63befa7, 0x2ba9660a, 0xf765a38b, 0xf273c9e7); - let key7 = m128i::from_i32(0xc0b0762d, 0x0c06d1fd, 0x915839de, 0x7a7cd609); - - let mut state0 = input[0]; - let mut state1 = input[1]; - let mut state2 = input[2]; - let mut state3 = input[3]; - - let mut out_ix = 0; + //debug_assert!(output_size % 4 == 0); + let mut result: Vec = Vec::with_capacity(output_size); + let key0: m128i = m128i::from_i32(0x99e5d23f, 0x2f546d2b, 0xd1833ddb, 0x6421aadd); + let key1: m128i = m128i::from_i32(0xa5dfcde5, 0x06f79d53, 0xb6913f55, 0xb20e3450); + let key2: m128i = m128i::from_i32(0x171c02bf, 0x0aa4679f, 0x515e7baf, 0x5c3ed904); + let key3: m128i = m128i::from_i32(0xd8ded291, 0xcd673785, 0xe78f5d08, 0x85623763); + let key4: m128i = m128i::from_i32(0x229effb4, 0x3d518b6d, 0xe3d6a7a6, 0xb5826f73); + let key5: m128i = m128i::from_i32(0xb272b7d2, 0xe9024d4e, 0x9c10b3d9, 0xc7566bf3); + let key6: m128i = m128i::from_i32(0xf63befa7, 0x2ba9660a, 0xf765a38b, 0xf273c9e7); + let key7: m128i = m128i::from_i32(0xc0b0762d, 0x0c06d1fd, 0x915839de, 0x7a7cd609); + + let mut state0: m128i = input[0]; + let mut state1: m128i = input[1]; + let mut state2: m128i = input[2]; + let mut state3: m128i = input[3]; + + let mut out_ix: usize = 0; while out_ix < output_size { state0 = state0.aesdec(key0); state1 = state1.aesenc(key0); diff --git a/src/randomx/m128.rs b/src/randomx/m128.rs index f08f11a..a545819 100644 --- a/src/randomx/m128.rs +++ b/src/randomx/m128.rs @@ -41,8 +41,8 @@ impl m128i { } pub fn as_i64(&self) -> (i64, i64) { unsafe { - let p1 = _mm_extract_epi64(self.0, 1); - let p2 = _mm_extract_epi64(self.0, 0); + let p1: i64 = _mm_extract_epi64(self.0, 1); + let p2: i64 = _mm_extract_epi64(self.0, 0); (p1, p2) } } diff --git a/src/randomx/memory.rs b/src/randomx/memory.rs index b5ce30d..ed8d69f 100644 --- a/src/randomx/memory.rs +++ b/src/randomx/memory.rs @@ -1,15 +1,12 @@ extern crate argon2; +use std::arch::x86_64::{_mm_prefetch, _MM_HINT_NTA}; use std::sync::{Arc, RwLock}; use std::time::Instant; -use std::arch::x86_64::{ - _mm_prefetch, - _MM_HINT_NTA -}; use self::argon2::block::Block; -use crate::hexbytes::hex2; use super::superscalar::{Blake2Generator, ScProgram}; +use crate::hexbytes::hex2; const RANDOMX_ARGON_LANES: u32 = 1; const RANDOMX_ARGON_MEMORY: u32 = 262144; @@ -137,9 +134,10 @@ impl VmMemoryAllocator { } } + //#[target_feature(enable = "avx2")] pub fn reallocate(&mut self, seed: String) { if seed != self.vm_memory_seed { - let mem_init_start = Instant::now(); + let mem_init_start: Instant = Instant::now(); self.vm_memory = Arc::new(VmMemory::full(&hex2(&seed))); self.vm_memory_seed = seed; println!( @@ -149,6 +147,8 @@ impl VmMemoryAllocator { ); } } + + //#[target_feature(enable = "avx2")] pub fn reallocate_light(&mut self, seed: String) { if seed != self.vm_memory_seed { let mem_init_start = Instant::now(); @@ -179,6 +179,7 @@ impl VmMemory { } } + //#[target_feature(enable = "avx2")] pub fn light(key: &[u8]) -> VmMemory { VmMemory { seed_memory: SeedMemory::new_initialised(key), @@ -186,9 +187,11 @@ impl VmMemory { dataset_memory: RwLock::new(Vec::with_capacity(0)), } } + + //#[target_feature(enable = "avx2")] pub fn full(key: &[u8]) -> VmMemory { - let seed_mem = SeedMemory::new_initialised(key); - let mem = vec![None; DATASET_ITEM_COUNT]; + let seed_mem: SeedMemory = SeedMemory::new_initialised(key); + let mem: Vec> = vec![None; DATASET_ITEM_COUNT]; VmMemory { seed_memory: seed_mem, cache: true, @@ -196,27 +199,31 @@ impl VmMemory { } } + //#[target_feature(enable = "avx2")] pub fn dataset_prefetch(&self, offset: u64) { - let item_num = offset / CACHE_LINE_SIZE; + let item_num: u64 = offset / CACHE_LINE_SIZE; if self.cache { - let mem = self.dataset_memory.read().unwrap(); - let rl_cached = &mem[item_num as usize]; + let mem: std::sync::RwLockReadGuard<'_, Vec>> = + self.dataset_memory.read().unwrap(); + let rl_cached: &Option<[u64; 8]> = &mem[item_num as usize]; if let Some(rl) = rl_cached { - unsafe{ - let raw : *const i8 = std::mem::transmute(rl); + unsafe { + let raw: *const i8 = std::mem::transmute(rl); _mm_prefetch(raw, _MM_HINT_NTA); } } } } + //#[target_feature(enable = "avx2")] pub fn dataset_read(&self, offset: u64, reg: &mut [u64; 8]) { - let item_num = offset / CACHE_LINE_SIZE; + let item_num: u64 = offset / CACHE_LINE_SIZE; if self.cache { { - let mem = self.dataset_memory.read().unwrap(); - let rl_cached = &mem[item_num as usize]; + let mem: std::sync::RwLockReadGuard<'_, Vec>> = + self.dataset_memory.read().unwrap(); + let rl_cached: &Option<[u64; 8]> = &mem[item_num as usize]; if let Some(rl) = rl_cached { for i in 0..8 { reg[i] ^= rl[i]; @@ -225,15 +232,16 @@ impl VmMemory { } } { - let rl = init_dataset_item(&self.seed_memory, item_num); - let mut mem_mut = self.dataset_memory.write().unwrap(); + let rl: [u64; 8] = init_dataset_item(&self.seed_memory, item_num); + let mut mem_mut: std::sync::RwLockWriteGuard<'_, Vec>> = + self.dataset_memory.write().unwrap(); mem_mut[item_num as usize] = Some(rl); for i in 0..8 { reg[i] ^= rl[i]; } } } else { - let rl = init_dataset_item(&self.seed_memory, item_num); + let rl: [u64; 8] = init_dataset_item(&self.seed_memory, item_num); for i in 0..8 { reg[i] ^= rl[i]; } diff --git a/src/randomx/program.rs b/src/randomx/program.rs index 1aa233c..7096fcc 100644 --- a/src/randomx/program.rs +++ b/src/randomx/program.rs @@ -43,7 +43,7 @@ pub enum Opcode { ISTORE = 0x100, } -#[derive(Debug,Display, PartialEq)] +#[derive(Debug, Display, PartialEq)] pub enum Store { NONE, //registers @@ -173,6 +173,7 @@ pub fn new_lcache_instr( } impl Instr { + //#[target_feature(enable = "avx2")] pub fn execute(&self, vm: &mut Vm) { (self.effect)(vm, self); } @@ -248,6 +249,7 @@ pub struct Program { } impl Program { + //#[target_feature(enable = "avx2")] pub fn from_bytes(bytes: Vec) -> Program { let mut entropy = Vec::with_capacity(16); let mut program = Vec::with_capacity((bytes.len() - 8) * 2); @@ -285,6 +287,7 @@ impl fmt::Display for Program { } #[allow(overflowing_literals)] +//#[target_feature(enable = "avx2")] pub fn decode_instruction(bytes: i64, i: i32, register_usage: &mut [i32; MAX_REG]) -> Instr { let op = bytes & 0xFF; let dst = ((bytes & 0xFF00) >> 8) as usize; diff --git a/src/randomx/superscalar.rs b/src/randomx/superscalar.rs index 5f08fbf..5d1282a 100644 --- a/src/randomx/superscalar.rs +++ b/src/randomx/superscalar.rs @@ -17,160 +17,160 @@ const MAX_THROWAWAY_COUNT: usize = 256; #[allow(nonstandard_style)] #[derive(Copy, Clone, Debug, PartialEq)] pub enum ScOpcode { - INVALID = -1, - ISUB_R = 0, - IXOR_R = 1, - IADD_RS = 2, - IMUL_R = 3, - IROR_C = 4, - IADD_C7 = 5, - IXOR_C7 = 6, - IADD_C8 = 7, - IXOR_C8 = 8, - IADD_C9 = 9, - IXOR_C9 = 10, - IMULH_R = 11, - ISMULH_R = 12, - IMUL_RCP = 13, - COUNT = 14, + INVALID = -1, + ISUB_R = 0, + IXOR_R = 1, + IADD_RS = 2, + IMUL_R = 3, + IROR_C = 4, + IADD_C7 = 5, + IXOR_C7 = 6, + IADD_C8 = 7, + IXOR_C8 = 8, + IADD_C9 = 9, + IXOR_C9 = 10, + IMULH_R = 11, + ISMULH_R = 12, + IMUL_RCP = 13, + COUNT = 14, } impl ScOpcode { - fn is_multiplication(self) -> bool { - self == ScOpcode::IMUL_R - || self == ScOpcode::IMULH_R - || self == ScOpcode::ISMULH_R - || self == ScOpcode::IMUL_RCP - } + fn is_multiplication(self) -> bool { + self == ScOpcode::IMUL_R + || self == ScOpcode::IMULH_R + || self == ScOpcode::ISMULH_R + || self == ScOpcode::IMUL_RCP + } } #[derive(Copy, Clone)] struct RegisterInfo { - pub last_op_group: ScOpcode, - pub latency: usize, - pub last_op_par: i32, + pub last_op_group: ScOpcode, + pub latency: usize, + pub last_op_par: i32, } impl RegisterInfo { - fn new() -> RegisterInfo { - RegisterInfo { - latency: 0, - last_op_group: ScOpcode::INVALID, - last_op_par: -1, - } - } + fn new() -> RegisterInfo { + RegisterInfo { + latency: 0, + last_op_group: ScOpcode::INVALID, + last_op_par: -1, + } + } } #[derive(Copy, Clone, Debug)] pub struct ScInstr<'a> { - pub info: &'a ScInstrInfo, - pub dst: i32, - pub src: i32, - pub mod_v: u8, - pub imm32: u32, - pub op_group: ScOpcode, - pub op_group_par: i32, - pub can_reuse: bool, - pub group_par_is_source: bool, + pub info: &'a ScInstrInfo, + pub dst: i32, + pub src: i32, + pub mod_v: u8, + pub imm32: u32, + pub op_group: ScOpcode, + pub op_group_par: i32, + pub can_reuse: bool, + pub group_par_is_source: bool, } impl ScInstr<'_> { - fn null() -> ScInstr<'static> { - ScInstr { - info: &NOP, - dst: -1, - src: -1, - mod_v: 0, - imm32: 0, - op_group: ScOpcode::INVALID, - can_reuse: false, - group_par_is_source: false, - op_group_par: -1, - } - } - - pub fn mod_shift(&self) -> u64 { - ((self.mod_v >> 2) % 4) as u64 - } - - fn select_destination( - &mut self, - cycle: usize, - allow_chain_mul: bool, - registers: &[RegisterInfo; 8], - gen: &mut Blake2Generator, - ) -> bool { - let mut available_registers = Vec::with_capacity(8); - for (i, v) in registers.iter().enumerate() { - if v.latency <= cycle - && (self.can_reuse || i as i32 != self.src) - && (allow_chain_mul - || self.op_group != ScOpcode::IMUL_R - || v.last_op_group != ScOpcode::IMUL_R) - && (v.last_op_group != self.op_group || v.last_op_par != self.op_group_par) - && (self.info.op != ScOpcode::IADD_RS || i != REG_NEEDS_DISPLACEMENT_IX) - { - available_registers.push(i); - } - } - self.select_register(&available_registers, gen, false) - } - - fn select_source( - &mut self, - cycle: usize, - registers: &[RegisterInfo; 8], - gen: &mut Blake2Generator, - ) -> bool { - let mut available_registers = Vec::with_capacity(8); - - for (i, v) in registers.iter().enumerate() { - if v.latency <= cycle { - available_registers.push(i); - } - } - - if available_registers.len() == 2 - && self.info.op == ScOpcode::IADD_RS - && (available_registers[0] == REG_NEEDS_DISPLACEMENT_IX - || available_registers[1] == REG_NEEDS_DISPLACEMENT_IX) - { - self.op_group_par = REG_NEEDS_DISPLACEMENT_IX as i32; - self.src = REG_NEEDS_DISPLACEMENT_IX as i32; - return true; - } - - if self.select_register(&available_registers, gen, true) { - if self.group_par_is_source { - self.op_group_par = self.src; - } - return true; - } - false - } - - fn select_register( - &mut self, - available_registers: &[usize], - gen: &mut Blake2Generator, - reg_src: bool, - ) -> bool { - if available_registers.is_empty() { - return false; - } - let index = if available_registers.len() > 1 { - gen.get_u32() as usize % available_registers.len() - } else { - 0 - }; - - if reg_src { - self.src = available_registers[index] as i32; - } else { - self.dst = available_registers[index] as i32; - } - true - } + fn null() -> ScInstr<'static> { + ScInstr { + info: &NOP, + dst: -1, + src: -1, + mod_v: 0, + imm32: 0, + op_group: ScOpcode::INVALID, + can_reuse: false, + group_par_is_source: false, + op_group_par: -1, + } + } + + pub fn mod_shift(&self) -> u64 { + ((self.mod_v >> 2) % 4) as u64 + } + + fn select_destination( + &mut self, + cycle: usize, + allow_chain_mul: bool, + registers: &[RegisterInfo; 8], + gen: &mut Blake2Generator, + ) -> bool { + let mut available_registers = Vec::with_capacity(8); + for (i, v) in registers.iter().enumerate() { + if v.latency <= cycle + && (self.can_reuse || i as i32 != self.src) + && (allow_chain_mul + || self.op_group != ScOpcode::IMUL_R + || v.last_op_group != ScOpcode::IMUL_R) + && (v.last_op_group != self.op_group || v.last_op_par != self.op_group_par) + && (self.info.op != ScOpcode::IADD_RS || i != REG_NEEDS_DISPLACEMENT_IX) + { + available_registers.push(i); + } + } + self.select_register(&available_registers, gen, false) + } + + fn select_source( + &mut self, + cycle: usize, + registers: &[RegisterInfo; 8], + gen: &mut Blake2Generator, + ) -> bool { + let mut available_registers = Vec::with_capacity(8); + + for (i, v) in registers.iter().enumerate() { + if v.latency <= cycle { + available_registers.push(i); + } + } + + if available_registers.len() == 2 + && self.info.op == ScOpcode::IADD_RS + && (available_registers[0] == REG_NEEDS_DISPLACEMENT_IX + || available_registers[1] == REG_NEEDS_DISPLACEMENT_IX) + { + self.op_group_par = REG_NEEDS_DISPLACEMENT_IX as i32; + self.src = REG_NEEDS_DISPLACEMENT_IX as i32; + return true; + } + + if self.select_register(&available_registers, gen, true) { + if self.group_par_is_source { + self.op_group_par = self.src; + } + return true; + } + false + } + + fn select_register( + &mut self, + available_registers: &[usize], + gen: &mut Blake2Generator, + reg_src: bool, + ) -> bool { + if available_registers.is_empty() { + return false; + } + let index = if available_registers.len() > 1 { + gen.get_u32() as usize % available_registers.len() + } else { + 0 + }; + + if reg_src { + self.src = available_registers[index] as i32; + } else { + self.dst = available_registers[index] as i32; + } + true + } } static SLOT_3L: [&ScInstrInfo; 4] = [&ISUB_R, &IXOR_R, &IMULH_R, &ISMULH_R]; @@ -181,302 +181,302 @@ static SLOT_9: [&ScInstrInfo; 2] = [&IXOR_C9, &IADD_C9]; static SLOT_10: &ScInstrInfo = &IMUL_RCP; fn is_zero_or_power_of_2(v: u32) -> bool { - v & v.wrapping_sub(1) == 0 + v & v.wrapping_sub(1) == 0 } impl ScInstr<'_> { - pub fn create_for_slot<'a>( - gen: &mut Blake2Generator, - slot_size: u32, - fetch_type: u32, - is_last: bool, - ) -> ScInstr<'a> { - match slot_size { - 3 => { - if is_last { - ScInstr::create(SLOT_3L[(gen.get_byte() & 3) as usize], gen) - } else { - ScInstr::create(SLOT_3L[(gen.get_byte() & 1) as usize], gen) - } - } - 4 => { - if fetch_type == 4 && !is_last { - ScInstr::create(&IMUL_R, gen) - } else { - ScInstr::create(SLOT_4[(gen.get_byte() & 1) as usize], gen) - } - } - 7 => ScInstr::create(SLOT_7[(gen.get_byte() & 1) as usize], gen), - 8 => ScInstr::create(SLOT_8[(gen.get_byte() & 1) as usize], gen), - 9 => ScInstr::create(SLOT_9[(gen.get_byte() & 1) as usize], gen), - 10 => ScInstr::create(SLOT_10, gen), - _ => panic!("illegal slot_size {}", slot_size), - } - } - - fn create<'a>(info: &'static ScInstrInfo, gen: &mut Blake2Generator) -> ScInstr<'a> { - match info.op { - ScOpcode::ISUB_R => ScInstr { - info, - dst: -1, - src: -1, - mod_v: 0, - imm32: 0, - op_group: ScOpcode::IADD_RS, - can_reuse: false, - group_par_is_source: true, - op_group_par: 0, - }, - ScOpcode::IXOR_R => ScInstr { - info, - dst: -1, - src: -1, - mod_v: 0, - imm32: 0, - op_group: ScOpcode::IXOR_R, - can_reuse: false, - group_par_is_source: true, - op_group_par: 0, - }, - ScOpcode::IADD_RS => ScInstr { - info, - dst: -1, - src: -1, - mod_v: gen.get_byte(), - imm32: 0, - op_group: ScOpcode::IADD_RS, - can_reuse: false, - group_par_is_source: true, - op_group_par: 0, - }, - ScOpcode::IMUL_R => ScInstr { - info, - dst: -1, - src: -1, - mod_v: 0, - imm32: 0, - op_group: ScOpcode::IMUL_R, - can_reuse: false, - group_par_is_source: true, - op_group_par: 0, - }, - ScOpcode::IROR_C => { - let mut imm32; - while { - imm32 = gen.get_byte() & 63; - imm32 == 0 - } {} - ScInstr { - info, - dst: -1, - src: -1, - mod_v: 0, - imm32: imm32 as u32, - op_group: ScOpcode::IROR_C, - can_reuse: false, - group_par_is_source: true, - op_group_par: 0, - } - } - ScOpcode::IADD_C7 | ScOpcode::IADD_C8 | ScOpcode::IADD_C9 => ScInstr { - info, - dst: -1, - src: -1, - mod_v: 0, - imm32: gen.get_u32(), - op_group: ScOpcode::IADD_C7, - can_reuse: false, - group_par_is_source: false, - op_group_par: -1, - }, - ScOpcode::IXOR_C7 | ScOpcode::IXOR_C8 | ScOpcode::IXOR_C9 => ScInstr { - info, - dst: -1, - src: -1, - mod_v: 0, - imm32: gen.get_u32(), - op_group: ScOpcode::IXOR_C7, - can_reuse: false, - group_par_is_source: false, - op_group_par: -1, - }, - ScOpcode::IMULH_R => ScInstr { - info, - dst: -1, - src: -1, - mod_v: 0, - imm32: 0, - op_group: ScOpcode::IMULH_R, - group_par_is_source: true, - can_reuse: false, - op_group_par: gen.get_u32() as i32, - }, - ScOpcode::ISMULH_R => ScInstr { - info, - dst: -1, - src: -1, - mod_v: 0, - imm32: 0, - op_group: ScOpcode::ISMULH_R, - group_par_is_source: true, - can_reuse: false, - op_group_par: gen.get_u32() as i32, - }, - ScOpcode::IMUL_RCP => { - let mut imm32; - while { - imm32 = gen.get_u32(); - is_zero_or_power_of_2(imm32) - } {} - ScInstr { - info, - dst: -1, - src: -1, - mod_v: 0, - imm32, - op_group: ScOpcode::IMUL_RCP, - can_reuse: false, - group_par_is_source: true, - op_group_par: -1, - } - } - ScOpcode::INVALID | ScOpcode::COUNT => panic!("invalid opcode {:?} here", info.op), - } - } + pub fn create_for_slot<'a>( + gen: &mut Blake2Generator, + slot_size: u32, + fetch_type: u32, + is_last: bool, + ) -> ScInstr<'a> { + match slot_size { + 3 => { + if is_last { + ScInstr::create(SLOT_3L[(gen.get_byte() & 3) as usize], gen) + } else { + ScInstr::create(SLOT_3L[(gen.get_byte() & 1) as usize], gen) + } + } + 4 => { + if fetch_type == 4 && !is_last { + ScInstr::create(&IMUL_R, gen) + } else { + ScInstr::create(SLOT_4[(gen.get_byte() & 1) as usize], gen) + } + } + 7 => ScInstr::create(SLOT_7[(gen.get_byte() & 1) as usize], gen), + 8 => ScInstr::create(SLOT_8[(gen.get_byte() & 1) as usize], gen), + 9 => ScInstr::create(SLOT_9[(gen.get_byte() & 1) as usize], gen), + 10 => ScInstr::create(SLOT_10, gen), + _ => panic!("illegal slot_size {}", slot_size), + } + } + + fn create<'a>(info: &'static ScInstrInfo, gen: &mut Blake2Generator) -> ScInstr<'a> { + match info.op { + ScOpcode::ISUB_R => ScInstr { + info, + dst: -1, + src: -1, + mod_v: 0, + imm32: 0, + op_group: ScOpcode::IADD_RS, + can_reuse: false, + group_par_is_source: true, + op_group_par: 0, + }, + ScOpcode::IXOR_R => ScInstr { + info, + dst: -1, + src: -1, + mod_v: 0, + imm32: 0, + op_group: ScOpcode::IXOR_R, + can_reuse: false, + group_par_is_source: true, + op_group_par: 0, + }, + ScOpcode::IADD_RS => ScInstr { + info, + dst: -1, + src: -1, + mod_v: gen.get_byte(), + imm32: 0, + op_group: ScOpcode::IADD_RS, + can_reuse: false, + group_par_is_source: true, + op_group_par: 0, + }, + ScOpcode::IMUL_R => ScInstr { + info, + dst: -1, + src: -1, + mod_v: 0, + imm32: 0, + op_group: ScOpcode::IMUL_R, + can_reuse: false, + group_par_is_source: true, + op_group_par: 0, + }, + ScOpcode::IROR_C => { + let mut imm32; + while { + imm32 = gen.get_byte() & 63; + imm32 == 0 + } {} + ScInstr { + info, + dst: -1, + src: -1, + mod_v: 0, + imm32: imm32 as u32, + op_group: ScOpcode::IROR_C, + can_reuse: false, + group_par_is_source: true, + op_group_par: 0, + } + } + ScOpcode::IADD_C7 | ScOpcode::IADD_C8 | ScOpcode::IADD_C9 => ScInstr { + info, + dst: -1, + src: -1, + mod_v: 0, + imm32: gen.get_u32(), + op_group: ScOpcode::IADD_C7, + can_reuse: false, + group_par_is_source: false, + op_group_par: -1, + }, + ScOpcode::IXOR_C7 | ScOpcode::IXOR_C8 | ScOpcode::IXOR_C9 => ScInstr { + info, + dst: -1, + src: -1, + mod_v: 0, + imm32: gen.get_u32(), + op_group: ScOpcode::IXOR_C7, + can_reuse: false, + group_par_is_source: false, + op_group_par: -1, + }, + ScOpcode::IMULH_R => ScInstr { + info, + dst: -1, + src: -1, + mod_v: 0, + imm32: 0, + op_group: ScOpcode::IMULH_R, + group_par_is_source: true, + can_reuse: false, + op_group_par: gen.get_u32() as i32, + }, + ScOpcode::ISMULH_R => ScInstr { + info, + dst: -1, + src: -1, + mod_v: 0, + imm32: 0, + op_group: ScOpcode::ISMULH_R, + group_par_is_source: true, + can_reuse: false, + op_group_par: gen.get_u32() as i32, + }, + ScOpcode::IMUL_RCP => { + let mut imm32; + while { + imm32 = gen.get_u32(); + is_zero_or_power_of_2(imm32) + } {} + ScInstr { + info, + dst: -1, + src: -1, + mod_v: 0, + imm32, + op_group: ScOpcode::IMUL_RCP, + can_reuse: false, + group_par_is_source: true, + op_group_par: -1, + } + } + ScOpcode::INVALID | ScOpcode::COUNT => panic!("invalid opcode {:?} here", info.op), + } + } } #[derive(Copy, Clone, PartialEq, Debug)] #[repr(u8)] pub enum ExecutionPort { - NULL = 0, - P0 = 1, - P1 = 2, - P5 = 4, - P01 = ExecutionPort::P0 as u8 | ExecutionPort::P1 as u8, - P05 = ExecutionPort::P0 as u8 | ExecutionPort::P5 as u8, - P015 = ExecutionPort::P0 as u8 | ExecutionPort::P1 as u8 | ExecutionPort::P5 as u8, + NULL = 0, + P0 = 1, + P1 = 2, + P5 = 4, + P01 = ExecutionPort::P0 as u8 | ExecutionPort::P1 as u8, + P05 = ExecutionPort::P0 as u8 | ExecutionPort::P5 as u8, + P015 = ExecutionPort::P0 as u8 | ExecutionPort::P1 as u8 | ExecutionPort::P5 as u8, } impl ExecutionPort { - fn is(self, check: ExecutionPort) -> bool { - (self as u8 & check as u8) != 0 - } + fn is(self, check: ExecutionPort) -> bool { + (self as u8 & check as u8) != 0 + } } #[derive(Debug)] pub struct ScMacroOp { - name: &'static str, - size: usize, - latency: usize, - uop1: ExecutionPort, - uop2: ExecutionPort, - dependent: bool, + name: &'static str, + size: usize, + latency: usize, + uop1: ExecutionPort, + uop2: ExecutionPort, + dependent: bool, } impl ScMacroOp { - pub const fn new( - name: &'static str, - size: usize, - latency: usize, - uop1: ExecutionPort, - uop2: ExecutionPort, - ) -> ScMacroOp { - ScMacroOp { - name, - size, - latency, - uop1, - uop2, - dependent: false, - } - } - pub const fn new_dep( - name: &'static str, - size: usize, - latency: usize, - uop1: ExecutionPort, - uop2: ExecutionPort, - ) -> ScMacroOp { - ScMacroOp { - name, - size, - latency, - uop1, - uop2, - dependent: true, - } - } - - pub fn is_eliminated(&self) -> bool { - self.uop1 == ExecutionPort::NULL - } - - pub fn is_simple(&self) -> bool { - self.uop2 == ExecutionPort::NULL - } + pub const fn new( + name: &'static str, + size: usize, + latency: usize, + uop1: ExecutionPort, + uop2: ExecutionPort, + ) -> ScMacroOp { + ScMacroOp { + name, + size, + latency, + uop1, + uop2, + dependent: false, + } + } + pub const fn new_dep( + name: &'static str, + size: usize, + latency: usize, + uop1: ExecutionPort, + uop2: ExecutionPort, + ) -> ScMacroOp { + ScMacroOp { + name, + size, + latency, + uop1, + uop2, + dependent: true, + } + } + + pub fn is_eliminated(&self) -> bool { + self.uop1 == ExecutionPort::NULL + } + + pub fn is_simple(&self) -> bool { + self.uop2 == ExecutionPort::NULL + } } static MOP_SUB_RR: ScMacroOp = - ScMacroOp::new("SUB_RR", 3, 1, ExecutionPort::P015, ExecutionPort::NULL); + ScMacroOp::new("SUB_RR", 3, 1, ExecutionPort::P015, ExecutionPort::NULL); static MOP_XOR_RR: ScMacroOp = - ScMacroOp::new("XOR_RR", 3, 1, ExecutionPort::P015, ExecutionPort::NULL); + ScMacroOp::new("XOR_RR", 3, 1, ExecutionPort::P015, ExecutionPort::NULL); static MOP_IMUL_R: ScMacroOp = ScMacroOp::new("IMUL_R", 3, 4, ExecutionPort::P1, ExecutionPort::P5); static MOP_MUL_R: ScMacroOp = ScMacroOp::new("MUL_R", 3, 4, ExecutionPort::P1, ExecutionPort::P5); static MOP_MOV_RR: ScMacroOp = - ScMacroOp::new("MOV_RR", 3, 1, ExecutionPort::NULL, ExecutionPort::NULL); + ScMacroOp::new("MOV_RR", 3, 1, ExecutionPort::NULL, ExecutionPort::NULL); static MOP_LEA_SIB: ScMacroOp = - ScMacroOp::new("LEA_SIB", 4, 1, ExecutionPort::P01, ExecutionPort::NULL); + ScMacroOp::new("LEA_SIB", 4, 1, ExecutionPort::P01, ExecutionPort::NULL); static MOP_IMUL_RR_DEP: ScMacroOp = - ScMacroOp::new_dep("IMUL_RR_DEP", 4, 3, ExecutionPort::P1, ExecutionPort::NULL); + ScMacroOp::new_dep("IMUL_RR_DEP", 4, 3, ExecutionPort::P1, ExecutionPort::NULL); static MOP_ROR_RI: ScMacroOp = - ScMacroOp::new("ROR_RI", 4, 1, ExecutionPort::P05, ExecutionPort::NULL); + ScMacroOp::new("ROR_RI", 4, 1, ExecutionPort::P05, ExecutionPort::NULL); static MOP_ADD_RI: ScMacroOp = - ScMacroOp::new("ADD_RI", 7, 1, ExecutionPort::P015, ExecutionPort::NULL); + ScMacroOp::new("ADD_RI", 7, 1, ExecutionPort::P015, ExecutionPort::NULL); static MOP_XOR_RI: ScMacroOp = - ScMacroOp::new("XOR_RI", 7, 1, ExecutionPort::P015, ExecutionPort::NULL); + ScMacroOp::new("XOR_RI", 7, 1, ExecutionPort::P015, ExecutionPort::NULL); static MOP_MOV_RI64: ScMacroOp = - ScMacroOp::new("MOV_RI64", 10, 1, ExecutionPort::P015, ExecutionPort::NULL); + ScMacroOp::new("MOV_RI64", 10, 1, ExecutionPort::P015, ExecutionPort::NULL); static MOP_IMUL_RR: ScMacroOp = - ScMacroOp::new("IMUL_RR", 4, 3, ExecutionPort::P1, ExecutionPort::NULL); + ScMacroOp::new("IMUL_RR", 4, 3, ExecutionPort::P1, ExecutionPort::NULL); #[allow(nonstandard_style)] #[derive(Debug)] pub struct ScInstrInfo { - pub op: ScOpcode, - pub macro_ops: &'static [&'static ScMacroOp], - pub result_op: usize, - pub src_op: i32, - pub dst_op: i32, + pub op: ScOpcode, + pub macro_ops: &'static [&'static ScMacroOp], + pub result_op: usize, + pub src_op: i32, + pub dst_op: i32, } impl ScInstrInfo { - pub const fn new( - op: ScOpcode, - macro_ops: &'static [&ScMacroOp], - result_op: usize, - dst_op: i32, - src_op: i32, - ) -> ScInstrInfo { - ScInstrInfo { - op, - macro_ops, - result_op, - src_op, - dst_op, - } - } - - pub fn size(&self) -> usize { - self.macro_ops.len() - } - - pub fn macro_op(&self, i: usize) -> &'static ScMacroOp { - self.macro_ops[i] - } + pub const fn new( + op: ScOpcode, + macro_ops: &'static [&ScMacroOp], + result_op: usize, + dst_op: i32, + src_op: i32, + ) -> ScInstrInfo { + ScInstrInfo { + op, + macro_ops, + result_op, + src_op, + dst_op, + } + } + + pub fn size(&self) -> usize { + self.macro_ops.len() + } + + pub fn macro_op(&self, i: usize) -> &'static ScMacroOp { + self.macro_ops[i] + } } static NOP: ScInstrInfo = ScInstrInfo::new(ScOpcode::INVALID, &[], 0, 0, 0); @@ -495,438 +495,439 @@ static IADD_C9: ScInstrInfo = ScInstrInfo::new(ScOpcode::IADD_C9, &[&MOP_ADD_RI] static IXOR_C9: ScInstrInfo = ScInstrInfo::new(ScOpcode::IXOR_C9, &[&MOP_XOR_RI], 0, 0, -1); static IMULH_R: ScInstrInfo = ScInstrInfo::new( - ScOpcode::IMULH_R, - &[&MOP_MOV_RR, &MOP_MUL_R, &MOP_MOV_RR], - 1, - 0, - 1, + ScOpcode::IMULH_R, + &[&MOP_MOV_RR, &MOP_MUL_R, &MOP_MOV_RR], + 1, + 0, + 1, ); static ISMULH_R: ScInstrInfo = ScInstrInfo::new( - ScOpcode::ISMULH_R, - &[&MOP_MOV_RR, &MOP_IMUL_R, &MOP_MOV_RR], - 1, - 0, - 1, + ScOpcode::ISMULH_R, + &[&MOP_MOV_RR, &MOP_IMUL_R, &MOP_MOV_RR], + 1, + 0, + 1, ); static IMUL_RCP: ScInstrInfo = ScInstrInfo::new( - ScOpcode::IMUL_RCP, - &[&MOP_MOV_RI64, &MOP_IMUL_RR_DEP], - 1, - 1, - -1, + ScOpcode::IMUL_RCP, + &[&MOP_MOV_RI64, &MOP_IMUL_RR_DEP], + 1, + 1, + -1, ); const BLAKE_GEN_DATA_LEN: usize = 64; pub struct Blake2Generator { - index: usize, - data: [u8; BLAKE_GEN_DATA_LEN], - gen_params: Params, + index: usize, + data: [u8; BLAKE_GEN_DATA_LEN], + gen_params: Params, } impl Blake2Generator { - pub fn new(seed: &[u8], nonce: u32) -> Blake2Generator { - debug_assert!(seed.len() <= BLAKE_GEN_DATA_LEN - 4); - let mut params = Params::new(); - params.hash_length(BLAKE_GEN_DATA_LEN); - - let mut key: [u8; 60] = [0; 60]; - key[..seed.len()].copy_from_slice(seed); - - let mut data: [u8; BLAKE_GEN_DATA_LEN] = [0; BLAKE_GEN_DATA_LEN]; - data[..BLAKE_GEN_DATA_LEN - 4].copy_from_slice(&key); - data[BLAKE_GEN_DATA_LEN - 4..BLAKE_GEN_DATA_LEN].copy_from_slice(&nonce.to_le_bytes()); - - Blake2Generator { - index: BLAKE_GEN_DATA_LEN, - data, - gen_params: params, - } - } - - pub fn get_byte(&mut self) -> u8 { - self.check_data(1); - let v = self.data[self.index]; - self.index += 1; - v - } - - pub fn get_u32(&mut self) -> u32 { - self.check_data(4); - let v = u32::from_le_bytes(self.data[self.index..(self.index + 4)].try_into().unwrap()); - self.index += 4; - v - } - fn check_data(&mut self, needed: usize) { - if self.index + needed > BLAKE_GEN_DATA_LEN { - let out = self.gen_params.hash(&self.data); - self.data = *out.as_array(); - self.index = 0; - } - } + pub fn new(seed: &[u8], nonce: u32) -> Blake2Generator { + debug_assert!(seed.len() <= BLAKE_GEN_DATA_LEN - 4); + let mut params = Params::new(); + params.hash_length(BLAKE_GEN_DATA_LEN); + + let mut key: [u8; 60] = [0; 60]; + key[..seed.len()].copy_from_slice(seed); + + let mut data: [u8; BLAKE_GEN_DATA_LEN] = [0; BLAKE_GEN_DATA_LEN]; + data[..BLAKE_GEN_DATA_LEN - 4].copy_from_slice(&key); + data[BLAKE_GEN_DATA_LEN - 4..BLAKE_GEN_DATA_LEN].copy_from_slice(&nonce.to_le_bytes()); + + Blake2Generator { + index: BLAKE_GEN_DATA_LEN, + data, + gen_params: params, + } + } + + pub fn get_byte(&mut self) -> u8 { + self.check_data(1); + let v = self.data[self.index]; + self.index += 1; + v + } + + pub fn get_u32(&mut self) -> u32 { + self.check_data(4); + let v = u32::from_le_bytes(self.data[self.index..(self.index + 4)].try_into().unwrap()); + self.index += 4; + v + } + fn check_data(&mut self, needed: usize) { + if self.index + needed > BLAKE_GEN_DATA_LEN { + let out = self.gen_params.hash(&self.data); + self.data = *out.as_array(); + self.index = 0; + } + } } pub struct DecoderBuffer { - index: u32, - counts: &'static [u32], + index: u32, + counts: &'static [u32], } static BUFFER_484: DecoderBuffer = DecoderBuffer { - index: 0, - counts: &[4, 8, 4], + index: 0, + counts: &[4, 8, 4], }; static BUFFER_7333: DecoderBuffer = DecoderBuffer { - index: 1, - counts: &[7, 3, 3, 3], + index: 1, + counts: &[7, 3, 3, 3], }; static BUFFER_3733: DecoderBuffer = DecoderBuffer { - index: 2, - counts: &[3, 7, 3, 3], + index: 2, + counts: &[3, 7, 3, 3], }; static BUFFER_493: DecoderBuffer = DecoderBuffer { - index: 3, - counts: &[4, 9, 3], + index: 3, + counts: &[4, 9, 3], }; static BUFFER_4444: DecoderBuffer = DecoderBuffer { - index: 4, - counts: &[4, 4, 4, 4], + index: 4, + counts: &[4, 4, 4, 4], }; static BUFFFER_3310: DecoderBuffer = DecoderBuffer { - index: 5, - counts: &[3, 3, 10], + index: 5, + counts: &[3, 3, 10], }; static DECODE_BUFFERS: [&DecoderBuffer; 4] = [&BUFFER_484, &BUFFER_7333, &BUFFER_3733, &BUFFER_493]; impl DecoderBuffer { - fn initial() -> DecoderBuffer { - DecoderBuffer { - index: 0, - counts: &[], - } - } - - pub fn size(&self) -> usize { - self.counts.len() - } - - pub fn fetch_next( - &self, - instr: &ScInstr, - decode_cycle: usize, - mul_count: usize, - gen: &mut Blake2Generator, - ) -> &'static DecoderBuffer { - if instr.info.op == ScOpcode::IMULH_R || instr.info.op == ScOpcode::ISMULH_R { - return &BUFFFER_3310; - } - if mul_count < decode_cycle + 1 { - return &BUFFER_4444; - } - if instr.info.op == ScOpcode::IMUL_RCP { - return if gen.get_byte() & 0x1 == 1 { - &BUFFER_484 - } else { - &BUFFER_493 - }; - } - let ix = gen.get_byte(); - DECODE_BUFFERS[(ix & 3) as usize] - } + fn initial() -> DecoderBuffer { + DecoderBuffer { + index: 0, + counts: &[], + } + } + + pub fn size(&self) -> usize { + self.counts.len() + } + + pub fn fetch_next( + &self, + instr: &ScInstr, + decode_cycle: usize, + mul_count: usize, + gen: &mut Blake2Generator, + ) -> &'static DecoderBuffer { + if instr.info.op == ScOpcode::IMULH_R || instr.info.op == ScOpcode::ISMULH_R { + return &BUFFFER_3310; + } + if mul_count < decode_cycle + 1 { + return &BUFFER_4444; + } + if instr.info.op == ScOpcode::IMUL_RCP { + return if gen.get_byte() & 0x1 == 1 { + &BUFFER_484 + } else { + &BUFFER_493 + }; + } + let ix = gen.get_byte(); + DECODE_BUFFERS[(ix & 3) as usize] + } } pub struct ScProgram<'a> { - pub prog: Vec>, - pub asic_latencies: Vec, - pub cpu_latencies: Vec, - pub address_reg: usize, - pub ipc: f64, - pub code_size: usize, - pub macro_ops: usize, - pub decode_cycles: usize, - pub cpu_latency: usize, - pub asic_latency: usize, - pub mul_count: usize, + pub prog: Vec>, + pub asic_latencies: Vec, + pub cpu_latencies: Vec, + pub address_reg: usize, + pub ipc: f64, + pub code_size: usize, + pub macro_ops: usize, + pub decode_cycles: usize, + pub cpu_latency: usize, + pub asic_latency: usize, + pub mul_count: usize, } impl fmt::Display for ScProgram<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for instr in &self.prog { - writeln!( - f, - "op: {:?}, src: {:?}, dst: {:?}", - instr.info.op, instr.src, instr.dst - ) - .unwrap(); - } - Ok(()) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for instr in &self.prog { + writeln!( + f, + "op: {:?}, src: {:?}, dst: {:?}", + instr.info.op, instr.src, instr.dst + ) + .unwrap(); + } + Ok(()) + } } impl ScProgram<'_> { - pub fn generate(gen: &mut Blake2Generator) -> ScProgram<'static> { - let mut prog = Vec::with_capacity(SUPERSCALAR_MAX_SIZE); - - let mut port_busy = [[ExecutionPort::NULL; 3]; CYCLE_MAP_SIZE]; - let mut registers = [RegisterInfo::new(); 8]; - - let mut macro_op_index = 0; - let mut code_size = 0; - let mut macro_op_count = 0; - let mut cycle = 0; - let mut dep_cycle = 0; - let mut retire_cycle = 0; - let mut ports_saturated = false; - let mut program_size = 0; - let mut mul_count = 0; - let mut decode_cycle = 0; - let mut throw_away_count = 0; - - let mut decode_buffer = &DecoderBuffer::initial(); - let mut current_instr = ScInstr::null(); - while decode_cycle < RANDOMX_SUPERSCALAR_LATENCY - && !ports_saturated - && program_size < SUPERSCALAR_MAX_SIZE - { - decode_buffer = decode_buffer.fetch_next(¤t_instr, decode_cycle, mul_count, gen); - let mut buffer_index = 0; - while buffer_index < decode_buffer.size() { - let top_cycle = cycle; - if macro_op_index >= current_instr.info.size() { - if ports_saturated || program_size >= SUPERSCALAR_MAX_SIZE { - break; - } - - current_instr = ScInstr::create_for_slot( - gen, - decode_buffer.counts[buffer_index], - decode_buffer.index, - decode_buffer.size() == buffer_index + 1, - ); - macro_op_index = 0 - } - - let mop = current_instr.info.macro_op(macro_op_index); - let schedule_cycle_mop = schedule_mop(false, mop, &mut port_busy, cycle, dep_cycle); - if schedule_cycle_mop.is_none() { - ports_saturated = true; - break; - } - - let mut schedule_cycle = schedule_cycle_mop.unwrap(); - if macro_op_index as i32 == current_instr.info.src_op { - let mut forward = 0; - while forward < LOOK_FORWARD_CYCLES - && !current_instr.select_source(schedule_cycle, ®isters, gen) - { - schedule_cycle += 1; - cycle += 1; - forward += 1; - } - - if forward == LOOK_FORWARD_CYCLES { - if throw_away_count < MAX_THROWAWAY_COUNT { - throw_away_count += 1; - macro_op_index = current_instr.info.size(); - continue; - } - current_instr = ScInstr::null(); - break; - } - } - if macro_op_index as i32 == current_instr.info.dst_op { - let mut forward = 0; - while forward < LOOK_FORWARD_CYCLES - && !current_instr.select_destination( - schedule_cycle, - throw_away_count > 0, - ®isters, - gen, - ) { - schedule_cycle += 1; - cycle += 1; - forward += 1; - } - if forward == LOOK_FORWARD_CYCLES { - if throw_away_count < MAX_THROWAWAY_COUNT { - throw_away_count += 1; - macro_op_index = current_instr.info.size(); - continue; - } - current_instr = ScInstr::null(); - break; - } - } - throw_away_count = 0; - - let schedule_cycle_mop = - schedule_mop(true, mop, &mut port_busy, schedule_cycle, schedule_cycle); - if schedule_cycle_mop.is_none() { - ports_saturated = true; - break; - } - schedule_cycle = schedule_cycle_mop.unwrap(); - dep_cycle = schedule_cycle + mop.latency; - - if macro_op_index == current_instr.info.result_op { - let mut ri = &mut registers[current_instr.dst as usize]; - retire_cycle = dep_cycle; - ri.latency = retire_cycle; - ri.last_op_group = current_instr.op_group; - ri.last_op_par = current_instr.op_group_par; - } - code_size += mop.size; - buffer_index += 1; - macro_op_index += 1; - macro_op_count += 1; - - if schedule_cycle >= RANDOMX_SUPERSCALAR_LATENCY { - ports_saturated = true; - } - cycle = top_cycle; - - if macro_op_index >= current_instr.info.size() { - if current_instr.info.op.is_multiplication() { - mul_count += 1; - } - prog.push(current_instr); - program_size += 1; - } - } - cycle += 1; - decode_cycle += 1; - } - - let ipc = macro_op_count as f64 / retire_cycle as f64; - let mut asic_latencies = vec![0; 8]; - for &instr in prog.iter().take(program_size) { - let lat_dst = asic_latencies[instr.dst as usize] + 1; - let lat_src = if instr.src < 0 || instr.src == instr.dst { - 0 - } else { - asic_latencies[instr.src as usize] + 1 - }; - asic_latencies[instr.dst as usize] = lat_dst.max(lat_src); - } - - let mut asic_latency_max = 0; - let mut address_reg = 0; - let mut cpu_latencies = vec![0; 8]; - for i in 0..8 { - if asic_latencies[i] > asic_latency_max { - asic_latency_max = asic_latencies[i]; - address_reg = i; - } - cpu_latencies[i] = registers[i].latency; - } - - ScProgram { - prog, - asic_latencies, - cpu_latencies, - address_reg, - ipc, - mul_count, - cpu_latency: retire_cycle, - asic_latency: asic_latency_max, - code_size, - macro_ops: macro_op_count, - decode_cycles: decode_cycle, - } - } - - pub fn execute(&self, ds: &mut [u64; 8]) { - for instr in &self.prog { - let dst = instr.dst as usize; - let src = instr.src as usize; - match instr.info.op { - ScOpcode::ISUB_R => ds[dst] = ds[dst].wrapping_sub(ds[src]), - ScOpcode::IXOR_R => ds[dst] ^= ds[src], - ScOpcode::IADD_RS => ds[dst] = ds[dst].wrapping_add(ds[src] << instr.mod_shift()), - ScOpcode::IMUL_R => { - ds[dst] = ds[dst].wrapping_mul(ds[src]); - } - ScOpcode::IROR_C => ds[dst] = ds[dst].rotate_right(instr.imm32), - ScOpcode::IADD_C7 | ScOpcode::IADD_C8 | ScOpcode::IADD_C9 => { - ds[dst] = ds[dst].wrapping_add(u64_from_u32_imm(instr.imm32)); - } - ScOpcode::IXOR_C7 | ScOpcode::IXOR_C8 | ScOpcode::IXOR_C9 => { - ds[dst] ^= u64_from_u32_imm(instr.imm32); - } - ScOpcode::IMULH_R => ds[dst] = mulh(ds[dst], ds[src]), - ScOpcode::ISMULH_R => ds[dst] = smulh(ds[dst], ds[src]), - ScOpcode::IMUL_RCP => { - ds[dst] = ds[dst].wrapping_mul(randomx_reciprocal(instr.imm32 as u64)) - } - ScOpcode::COUNT => panic!("COUNT execution tried"), - ScOpcode::INVALID => panic!("INVALLID execution tried"), - } - } - } + pub fn generate(gen: &mut Blake2Generator) -> ScProgram<'static> { + let mut prog = Vec::with_capacity(SUPERSCALAR_MAX_SIZE); + + let mut port_busy = [[ExecutionPort::NULL; 3]; CYCLE_MAP_SIZE]; + let mut registers = [RegisterInfo::new(); 8]; + + let mut macro_op_index = 0; + let mut code_size = 0; + let mut macro_op_count = 0; + let mut cycle = 0; + let mut dep_cycle = 0; + let mut retire_cycle = 0; + let mut ports_saturated = false; + let mut program_size = 0; + let mut mul_count = 0; + let mut decode_cycle = 0; + let mut throw_away_count = 0; + + let mut decode_buffer = &DecoderBuffer::initial(); + let mut current_instr = ScInstr::null(); + while decode_cycle < RANDOMX_SUPERSCALAR_LATENCY + && !ports_saturated + && program_size < SUPERSCALAR_MAX_SIZE + { + decode_buffer = decode_buffer.fetch_next(¤t_instr, decode_cycle, mul_count, gen); + let mut buffer_index = 0; + while buffer_index < decode_buffer.size() { + let top_cycle = cycle; + if macro_op_index >= current_instr.info.size() { + if ports_saturated || program_size >= SUPERSCALAR_MAX_SIZE { + break; + } + + current_instr = ScInstr::create_for_slot( + gen, + decode_buffer.counts[buffer_index], + decode_buffer.index, + decode_buffer.size() == buffer_index + 1, + ); + macro_op_index = 0 + } + + let mop = current_instr.info.macro_op(macro_op_index); + let schedule_cycle_mop = schedule_mop(false, mop, &mut port_busy, cycle, dep_cycle); + if schedule_cycle_mop.is_none() { + ports_saturated = true; + break; + } + + let mut schedule_cycle = schedule_cycle_mop.unwrap(); + if macro_op_index as i32 == current_instr.info.src_op { + let mut forward = 0; + while forward < LOOK_FORWARD_CYCLES + && !current_instr.select_source(schedule_cycle, ®isters, gen) + { + schedule_cycle += 1; + cycle += 1; + forward += 1; + } + + if forward == LOOK_FORWARD_CYCLES { + if throw_away_count < MAX_THROWAWAY_COUNT { + throw_away_count += 1; + macro_op_index = current_instr.info.size(); + continue; + } + current_instr = ScInstr::null(); + break; + } + } + if macro_op_index as i32 == current_instr.info.dst_op { + let mut forward = 0; + while forward < LOOK_FORWARD_CYCLES + && !current_instr.select_destination( + schedule_cycle, + throw_away_count > 0, + ®isters, + gen, + ) + { + schedule_cycle += 1; + cycle += 1; + forward += 1; + } + if forward == LOOK_FORWARD_CYCLES { + if throw_away_count < MAX_THROWAWAY_COUNT { + throw_away_count += 1; + macro_op_index = current_instr.info.size(); + continue; + } + current_instr = ScInstr::null(); + break; + } + } + throw_away_count = 0; + + let schedule_cycle_mop = + schedule_mop(true, mop, &mut port_busy, schedule_cycle, schedule_cycle); + if schedule_cycle_mop.is_none() { + ports_saturated = true; + break; + } + schedule_cycle = schedule_cycle_mop.unwrap(); + dep_cycle = schedule_cycle + mop.latency; + + if macro_op_index == current_instr.info.result_op { + let ri = &mut registers[current_instr.dst as usize]; + retire_cycle = dep_cycle; + ri.latency = retire_cycle; + ri.last_op_group = current_instr.op_group; + ri.last_op_par = current_instr.op_group_par; + } + code_size += mop.size; + buffer_index += 1; + macro_op_index += 1; + macro_op_count += 1; + + if schedule_cycle >= RANDOMX_SUPERSCALAR_LATENCY { + ports_saturated = true; + } + cycle = top_cycle; + + if macro_op_index >= current_instr.info.size() { + if current_instr.info.op.is_multiplication() { + mul_count += 1; + } + prog.push(current_instr); + program_size += 1; + } + } + cycle += 1; + decode_cycle += 1; + } + + let ipc = macro_op_count as f64 / retire_cycle as f64; + let mut asic_latencies = vec![0; 8]; + for &instr in prog.iter().take(program_size) { + let lat_dst = asic_latencies[instr.dst as usize] + 1; + let lat_src = if instr.src < 0 || instr.src == instr.dst { + 0 + } else { + asic_latencies[instr.src as usize] + 1 + }; + asic_latencies[instr.dst as usize] = lat_dst.max(lat_src); + } + + let mut asic_latency_max = 0; + let mut address_reg = 0; + let mut cpu_latencies = vec![0; 8]; + for i in 0..8 { + if asic_latencies[i] > asic_latency_max { + asic_latency_max = asic_latencies[i]; + address_reg = i; + } + cpu_latencies[i] = registers[i].latency; + } + + ScProgram { + prog, + asic_latencies, + cpu_latencies, + address_reg, + ipc, + mul_count, + cpu_latency: retire_cycle, + asic_latency: asic_latency_max, + code_size, + macro_ops: macro_op_count, + decode_cycles: decode_cycle, + } + } + + pub fn execute(&self, ds: &mut [u64; 8]) { + for instr in &self.prog { + let dst = instr.dst as usize; + let src = instr.src as usize; + match instr.info.op { + ScOpcode::ISUB_R => ds[dst] = ds[dst].wrapping_sub(ds[src]), + ScOpcode::IXOR_R => ds[dst] ^= ds[src], + ScOpcode::IADD_RS => ds[dst] = ds[dst].wrapping_add(ds[src] << instr.mod_shift()), + ScOpcode::IMUL_R => { + ds[dst] = ds[dst].wrapping_mul(ds[src]); + } + ScOpcode::IROR_C => ds[dst] = ds[dst].rotate_right(instr.imm32), + ScOpcode::IADD_C7 | ScOpcode::IADD_C8 | ScOpcode::IADD_C9 => { + ds[dst] = ds[dst].wrapping_add(u64_from_u32_imm(instr.imm32)); + } + ScOpcode::IXOR_C7 | ScOpcode::IXOR_C8 | ScOpcode::IXOR_C9 => { + ds[dst] ^= u64_from_u32_imm(instr.imm32); + } + ScOpcode::IMULH_R => ds[dst] = mulh(ds[dst], ds[src]), + ScOpcode::ISMULH_R => ds[dst] = smulh(ds[dst], ds[src]), + ScOpcode::IMUL_RCP => { + ds[dst] = ds[dst].wrapping_mul(randomx_reciprocal(instr.imm32 as u64)) + } + ScOpcode::COUNT => panic!("COUNT execution tried"), + ScOpcode::INVALID => panic!("INVALLID execution tried"), + } + } + } } #[allow(clippy::unnecessary_unwrap)] fn schedule_mop( - commit: bool, - mop: &ScMacroOp, - port_busy: &mut [[ExecutionPort; 3]; CYCLE_MAP_SIZE], - cycle_in: usize, - dep_cycle: usize, + commit: bool, + mop: &ScMacroOp, + port_busy: &mut [[ExecutionPort; 3]; CYCLE_MAP_SIZE], + cycle_in: usize, + dep_cycle: usize, ) -> Option { - let mut cycle = if mop.dependent { - usize::max(cycle_in, dep_cycle) - } else { - cycle_in - }; - - if mop.is_eliminated() { - return Some(cycle); - } else if mop.is_simple() { - return schedule_uop(commit, mop.uop1, port_busy, cycle); - } else { - while cycle < CYCLE_MAP_SIZE { - let cycle_1 = schedule_uop(false, mop.uop1, port_busy, cycle); - let cycle_2 = schedule_uop(false, mop.uop2, port_busy, cycle); - - if cycle_1.is_some() && cycle_1 == cycle_2 { - if commit { - schedule_uop(true, mop.uop1, port_busy, cycle_1.unwrap()); - schedule_uop(true, mop.uop2, port_busy, cycle_2.unwrap()); - } - return cycle_1; - } - cycle += 1 - } - } - None + let mut cycle = if mop.dependent { + usize::max(cycle_in, dep_cycle) + } else { + cycle_in + }; + + if mop.is_eliminated() { + return Some(cycle); + } else if mop.is_simple() { + return schedule_uop(commit, mop.uop1, port_busy, cycle); + } else { + while cycle < CYCLE_MAP_SIZE { + let cycle_1 = schedule_uop(false, mop.uop1, port_busy, cycle); + let cycle_2 = schedule_uop(false, mop.uop2, port_busy, cycle); + + if cycle_1.is_some() && cycle_1 == cycle_2 { + if commit { + schedule_uop(true, mop.uop1, port_busy, cycle_1.unwrap()); + schedule_uop(true, mop.uop2, port_busy, cycle_2.unwrap()); + } + return cycle_1; + } + cycle += 1 + } + } + None } fn schedule_uop( - commit: bool, - uop: ExecutionPort, - port_busy: &mut [[ExecutionPort; 3]; CYCLE_MAP_SIZE], - cycle_in: usize, + commit: bool, + uop: ExecutionPort, + port_busy: &mut [[ExecutionPort; 3]; CYCLE_MAP_SIZE], + cycle_in: usize, ) -> Option { - let mut cycle = cycle_in; - while cycle < CYCLE_MAP_SIZE { - if uop.is(ExecutionPort::P5) && port_busy[cycle][2] == ExecutionPort::NULL { - if commit { - port_busy[cycle][2] = uop; - } - return Some(cycle); - } - if uop.is(ExecutionPort::P0) && port_busy[cycle][0] == ExecutionPort::NULL { - if commit { - port_busy[cycle][0] = uop; - } - return Some(cycle); - } - if uop.is(ExecutionPort::P1) && port_busy[cycle][1] == ExecutionPort::NULL { - if commit { - port_busy[cycle][1] = uop; - } - return Some(cycle); - } - cycle += 1 - } - None + let mut cycle = cycle_in; + while cycle < CYCLE_MAP_SIZE { + if uop.is(ExecutionPort::P5) && port_busy[cycle][2] == ExecutionPort::NULL { + if commit { + port_busy[cycle][2] = uop; + } + return Some(cycle); + } + if uop.is(ExecutionPort::P0) && port_busy[cycle][0] == ExecutionPort::NULL { + if commit { + port_busy[cycle][0] = uop; + } + return Some(cycle); + } + if uop.is(ExecutionPort::P1) && port_busy[cycle][1] == ExecutionPort::NULL { + if commit { + port_busy[cycle][1] = uop; + } + return Some(cycle); + } + cycle += 1 + } + None } diff --git a/src/randomx/vm.rs b/src/randomx/vm.rs index acf384c..d00c189 100644 --- a/src/randomx/vm.rs +++ b/src/randomx/vm.rs @@ -49,25 +49,30 @@ pub struct MemoryRegister { } pub struct Register { - pub r: [u64; MAX_REG as usize], - pub f: [m128d; MAX_FLOAT_REG as usize], - pub e: [m128d; MAX_FLOAT_REG as usize], - pub a: [m128d; MAX_FLOAT_REG as usize], + pub r: [u64; MAX_REG], + pub f: [m128d; MAX_FLOAT_REG], + pub e: [m128d; MAX_FLOAT_REG], + pub a: [m128d; MAX_FLOAT_REG], } pub fn new_register() -> Register { Register { - r: [0; MAX_REG as usize], - f: [m128d::zero(); MAX_FLOAT_REG as usize], - e: [m128d::zero(); MAX_FLOAT_REG as usize], - a: [m128d::zero(); MAX_FLOAT_REG as usize], + r: [0; MAX_REG], + f: [m128d::zero(); MAX_FLOAT_REG], + e: [m128d::zero(); MAX_FLOAT_REG], + a: [m128d::zero(); MAX_FLOAT_REG], } } +fn div(num: u32, to: f32) -> u32 { + let f: f32 = num as f32 * to; + f as u32 +} + impl Register { pub fn to_bytes(&self) -> [u8; 256] { - let mut bytes = [0; 256]; - let mut offset = 0; + let mut bytes: [u8; 256] = [0; 256]; + let mut offset: usize = 0; for i in 0..MAX_REG { Register::copy_into_le(&mut bytes, offset, self.r[i]); offset += 1; @@ -101,7 +106,7 @@ impl Register { } fn copy_into_le(bytes: &mut [u8; 256], offset: usize, u: u64) { - let reg_bytes = u.to_le_bytes(); + let reg_bytes: [u8; 8] = u.to_le_bytes(); for k in 0..8 { bytes[offset * 8 + k] = reg_bytes[k]; } @@ -124,6 +129,7 @@ pub struct Vm { } impl Vm { + //#[target_feature(enable = "avx2")] pub fn init_vm(&mut self, prog: &Program) { self.reg.a[0] = m128d::from_u64( small_positive_float_bit(prog.entropy[1]), @@ -165,38 +171,41 @@ impl Vm { } } + //#[target_feature(enable = "avx2")] pub fn init_scratchpad(&mut self, seed: &[m128i; 4]) -> [m128i; 4] { fill_aes_1rx4_u64(seed, &mut self.scratchpad) } + //#[target_feature(enable = "avx2")] pub fn calculate_hash(&mut self, input: &[u8]) -> Hash { - let hash = blake2b(input); - let seed = hash_to_m128i_array(&hash); + let hash: Hash = blake2b(input); + let seed: [m128i; 4] = hash_to_m128i_array(&hash); - let mut tmp_hash = self.init_scratchpad(&seed); + let mut tmp_hash: [m128i; 4] = self.init_scratchpad(&seed); self.reset_rounding_mode(); for _ in 0..(RANDOMX_PROGRAM_COUNT - 1) { self.run(&tmp_hash); - let blake_result = blake2b(&self.reg.to_bytes()); + let blake_result: Hash = blake2b(&self.reg.to_bytes()); tmp_hash = hash_to_m128i_array(&blake_result); } self.run(&tmp_hash); - let final_hash = hash_aes_1rx4(&self.scratchpad); + let final_hash: [m128i; 4] = hash_aes_1rx4(&self.scratchpad); self.reg.a[0] = final_hash[0].as_m128d(); self.reg.a[1] = final_hash[1].as_m128d(); self.reg.a[2] = final_hash[2].as_m128d(); self.reg.a[3] = final_hash[3].as_m128d(); - let mut params = Params::new(); + let mut params: Params = Params::new(); params.hash_length(RANDOMX_HASH_SIZE); params.hash(&self.reg.to_bytes()) } /// Runs one round + //#[target_feature(enable = "avx2")] pub fn run(&mut self, seed: &[m128i; 4]) { - let prog = Program::from_bytes(gen_program_aes_4rx4(seed, 136)); + let prog: Program = Program::from_bytes(gen_program_aes_4rx4(seed, 136)); self.init_vm(&prog); @@ -204,14 +213,17 @@ impl Vm { let mut sp_addr_1: u32 = self.mem_reg.ma as u32; for _ in 0..RANDOMX_PROGRAM_ITERATIONS { - let sp_mix = self.reg.r[self.config.read_reg[0]] ^ self.reg.r[self.config.read_reg[1]]; + let sp_mix: u64 = + self.reg.r[self.config.read_reg[0]] ^ self.reg.r[self.config.read_reg[1]]; sp_addr_0 ^= sp_mix as u32; sp_addr_0 &= SCRATCHPAD_L3_MASK_U32; - sp_addr_0 /= 8; + //sp_addr_0 /= 8; + sp_addr_0 = div(sp_addr_0, 0.125); sp_addr_1 ^= (sp_mix >> 32) as u32; sp_addr_1 &= SCRATCHPAD_L3_MASK_U32; - sp_addr_1 /= 8; + //sp_addr_1 /= 8; + sp_addr_1 = div(sp_addr_1, 0.125); for i in 0..MAX_REG { self.reg.r[i] ^= self.scratchpad[sp_addr_0 as usize + i]; @@ -229,7 +241,7 @@ impl Vm { self.pc = 0; while self.pc < RANDOMX_PROGRAM_SIZE { - let instr = &prog.program[self.pc as usize]; + let instr: &Instr = &prog.program[self.pc as usize]; instr.execute(self); self.pc += 1; } @@ -254,7 +266,7 @@ impl Vm { for i in 0..MAX_FLOAT_REG { let (u1, u0) = self.reg.f[i].as_u64(); - let ix = sp_addr_0 as usize + 2 * i; + let ix: usize = sp_addr_0 as usize + 2 * i; self.scratchpad[ix] = u0; self.scratchpad[ix + 1] = u1; } @@ -263,22 +275,25 @@ impl Vm { } } + //#[target_feature(enable = "avx2")] pub fn reset_rounding_mode(&mut self) { unsafe { _mm_setcsr(MXCSR_DEFAULT); } } + //#[target_feature(enable = "avx2")] pub fn set_rounding_mode(&mut self, mode: u32) { unsafe { _mm_setcsr(MXCSR_DEFAULT | (mode << 13)) } } + //#[target_feature(enable = "avx2")] pub fn get_rounding_mode(&self) -> u32 { unsafe { (_mm_getcsr() >> 13) & 3 } } //f... - + //#[target_feature(enable = "avx2")] pub fn exec_fswap_r(&mut self, instr: &Instr) { let v_dst = self.read_float_reg(&instr.dst); self.write_float_reg(&instr.dst, v_dst.shuffle_1(&v_dst)); @@ -449,10 +464,10 @@ impl Vm { } //c.. - + //#[target_feature(enable = "avx2")] pub fn exec_cfround(&mut self, instr: &Instr) { - let v_src = self.read_r(&instr.src); - let mode = (v_src.rotate_right(instr.imm.unwrap() as u32) % 4) as u32; + let v_src: u64 = self.read_r(&instr.src); + let mode: u32 = (v_src.rotate_right(instr.imm.unwrap() as u32) % 4) as u32; self.set_rounding_mode(mode); } @@ -542,7 +557,7 @@ impl Vm { } } fn scratchpad_src_ix(&self, instr: &Instr) -> usize { - let imm = u64_from_i32_imm(instr.imm.unwrap()); + let imm: u64 = u64_from_i32_imm(instr.imm.unwrap()); let addr: usize = match &instr.src { Store::L1(d) => (self.read_r(d).wrapping_add(imm)) & SCRATCHPAD_L1_MASK, Store::L2(d) => (self.read_r(d).wrapping_add(imm)) & SCRATCHPAD_L2_MASK, @@ -555,7 +570,7 @@ impl Vm { } fn scratchpad_dst_ix(&self, instr: &Instr) -> usize { - let imm = u64_from_i32_imm(instr.imm.unwrap()); + let imm: u64 = u64_from_i32_imm(instr.imm.unwrap()); let addr: usize = match &instr.dst { Store::L1(d) => (self.read_r(d).wrapping_add(imm)) & SCRATCHPAD_L1_MASK, Store::L2(d) => (self.read_r(d).wrapping_add(imm)) & SCRATCHPAD_L2_MASK, @@ -568,18 +583,18 @@ impl Vm { } fn mask_register_exponent_mantissa(&self, v: m128d) -> m128d { - let mantissa_mask = m128d::from_u64(DYNAMIC_MANTISSA_MASK, DYNAMIC_MANTISSA_MASK); - let exponent_mask = m128d::from_u64(self.config.e_mask[1], self.config.e_mask[0]); + let mantissa_mask: m128d = m128d::from_u64(DYNAMIC_MANTISSA_MASK, DYNAMIC_MANTISSA_MASK); + let exponent_mask: m128d = m128d::from_u64(self.config.e_mask[1], self.config.e_mask[0]); (v & mantissa_mask) | exponent_mask } } pub fn hash_to_m128i_array(hash: &Hash) -> [m128i; 4] { - let bytes = hash.as_bytes(); - let i1 = m128i::from_u8(&bytes[0..16]); - let i2 = m128i::from_u8(&bytes[16..32]); - let i3 = m128i::from_u8(&bytes[32..48]); - let i4 = m128i::from_u8(&bytes[48..64]); + let bytes: &[u8] = hash.as_bytes(); + let i1: m128i = m128i::from_u8(&bytes[0..16]); + let i2: m128i = m128i::from_u8(&bytes[16..32]); + let i3: m128i = m128i::from_u8(&bytes[32..48]); + let i4: m128i = m128i::from_u8(&bytes[48..64]); [i1, i2, i3, i4] } @@ -601,22 +616,25 @@ pub fn is_zero_or_power_of_2(imm: u64) -> bool { imm & imm.wrapping_sub(1) == 0 } +//#[target_feature(enable = "avx2")] fn small_positive_float_bit(entropy: u64) -> u64 { - let mut exponent = entropy >> 59; //0..31 - let mantissa = entropy & MANTISSA_MASK; + let mut exponent: u64 = entropy >> 59; //0..31 + let mantissa: u64 = entropy & MANTISSA_MASK; exponent += EXPONENT_BIAS; exponent &= EXPONENT_MASK; exponent <<= MANTISSA_SIZE; exponent | mantissa } +//#[target_feature(enable = "avx2")] fn float_mask(entropy: u64) -> u64 { - let mask22bit = (1 << 22) - 1; + let mask22bit: u64 = (1 << 22) - 1; entropy & mask22bit | static_exponent(entropy) } +//#[target_feature(enable = "avx2")] fn static_exponent(entropy: u64) -> u64 { - let mut exponent = EXPONENT_BITS; + let mut exponent: u64 = EXPONENT_BITS; exponent |= (entropy >> (64 - STATIC_EXPONENT_BITS)) << DYNAMIC_EXPONENT_BITS; exponent << MANTISSA_SIZE } diff --git a/src/request.rs b/src/request.rs index 9a2b183..917f9a6 100644 --- a/src/request.rs +++ b/src/request.rs @@ -11,14 +11,14 @@ use std::{ sync::Arc, }; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct Login { pub login: String, pub pass: String, pub agent: String, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Clone)] pub struct Request<'a, T> where T: TraitDeserialize<'a> + TraitSerialize + std::fmt::Debug, @@ -45,13 +45,16 @@ pub enum MessageType { Submit(Share), KeepAlive(KeepAlive), } + +//#[target_feature(enable = "avx2")] pub fn job_listener( mut stream_r: BufReader, sender: tokio::sync::mpsc::UnboundedSender<(block::Block, Arc)>, ) { - let mut vm_mem_alloc = randomx::memory::VmMemoryAllocator::initial(); + let mut vm_mem_alloc: randomx::memory::VmMemoryAllocator = + randomx::memory::VmMemoryAllocator::initial(); loop { - let mut buffer = String::new(); + let mut buffer: String = String::new(); loop { match stream_r.read_line(&mut buffer) { Ok(_o) => { diff --git a/src/save.txt b/src/save.txt deleted file mode 100644 index 8356051..0000000 --- a/src/save.txt +++ /dev/null @@ -1,48 +0,0 @@ -fn mine_loop(block_number:u64,transaction:u64,prev_hash:String) -> Option { - let mut lowest = u64::MAX; - let mut lowest_block = String::new(); - let context = Context::new(prev_hash.as_bytes(), false); - let hasher = Hasher::new(std::sync::Arc::new(context)); - for nonce in 0..NONCE { - let base_text = format!("{}{}{}{}",block_number,transaction,prev_hash,nonce); - let new_block = hex_digest(Algorithm::SHA256,base_text/*[24..]*/.as_bytes()); - let out = hasher.hash(new_block.as_bytes()); - let n = NumberReader::new(Cursor::new(new_block.as_bytes())).read_u64().unwrap(); - if out.meets_difficulty(Difficulty::new(STARTING_DIFFICULTY as u32)) { - let submit = Submit { - method:String::from("submit"), - params:Params { - id: String::from("null"), - job_id: String::from("null"), - nonce: nonce.to_string(), - result: new_block - }, - id:1 - }; - println!("found new hash {}",out.leading_zeros()); - println!("Nonce {}",nonce); - return Some(submit); - } else if lowest as u32 > out.leading_zeros() { - println!("new low found {n}"); - lowest = n; - lowest_block = new_block; - } - } - println!("could not find hash lowest was:{}",lowest); - println!("lowest block was {}",lowest_block); - None -} - -#[derive(Debug,Deserialize,Serialize)] -struct Submit { - method:String, - params: Params, - id:u32 -} -#[derive(Debug,Deserialize,Serialize)] -struct Params { - id:String, - job_id:String, - nonce:String, - result:String -} diff --git a/src/tcp.rs b/src/tcp.rs index 91cf137..19681fb 100644 --- a/src/tcp.rs +++ b/src/tcp.rs @@ -1,19 +1,16 @@ use crate::request; -use tokio::sync::mpsc::UnboundedReceiver; -use serde::{Serialize,Deserialize}; +use serde::{Deserialize, Serialize}; +use std::io::Write; use std::net::TcpStream; -use std::{ - sync::{Arc,atomic::{Ordering, AtomicUsize},Mutex}, - thread::sleep, - time::Duration, - io::{self,Write,Cursor, Read, BufWriter,BufRead, BufReader}, - cmp::min, fmt::format, ops::{Deref, Index} -}; +use tokio::sync::mpsc::UnboundedReceiver; type BoxError = Box; -pub fn connect(addr:&str,request:request::Request) -> Result { - let mut stream = TcpStream::connect(addr)?; +pub fn connect( + addr: &str, + request: request::Request, +) -> Result { + let mut stream: TcpStream = TcpStream::connect(addr)?; stream.set_nodelay(true)?; serde_json::to_writer(&mut stream, &request)?; writeln!(&mut stream)?; @@ -22,12 +19,13 @@ pub fn connect(addr:&str,request:request::Request) -> Result, + pub stream: TcpStream, + pub reciever: UnboundedReceiver, } impl Client { - pub fn send<'a,T>(&mut self,request:request::Request<'a,T>) -> Result<(),BoxError> - where T:Serialize + Deserialize<'a> + std::fmt::Debug + pub fn send<'a, T>(&mut self, request: request::Request<'a, T>) -> Result<(), BoxError> + where + T: Serialize + Deserialize<'a> + std::fmt::Debug, { serde_json::to_writer(&mut self.stream, &request).unwrap(); writeln!(&mut self.stream).unwrap(); @@ -41,21 +39,21 @@ impl Client { request::MessageType::Submit(submit) => { println!("recieved share"); let request = request::Request { - id:1, - method:"submit".to_string(), - params:&submit + id: 1, + method: "submit".to_string(), + params: &submit, }; self.send(request).unwrap(); println!("submitted share"); - }, + } request::MessageType::KeepAlive(keep_alive) => { - let req = request::Request { - id:1, - method:"keepalived".to_string(), - params: &keep_alive + let req = request::Request { + id: 1, + method: "keepalived".to_string(), + params: &keep_alive, }; self.send(req).unwrap(); - }, + } } } }