diff --git a/Cargo.toml b/Cargo.toml index 59ef1684dffc..36c78eca73bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,7 +68,7 @@ futures-rustls = {version = "0.26.0", default-features = false, features = ["log # Pluggable Transports socket2 = {version = "0.5.7", features = ["all"], optional = true} -arti-client = {version = "0.23.0", default-features = false, features = ["async-std", "compression", "error_detail", "rustls", "accel-sha1-asm", "onion-service-client", "onion-service-service"], optional = true} +arti-client = {version = "0.23.0", default-features = false, features = ["async-std", "compression", "error_detail", "rustls", "onion-service-client", "onion-service-service"], optional = true} tor-error = {version = "0.23.0", optional = true} tor-rtcompat = {version = "0.23.0", features = ["async-std", "rustls"], optional = true} tor-hscrypto = {version = "0.23.0", optional = true} @@ -201,7 +201,7 @@ p2p-tor = [ "tor-cell", ] -net = [ +net-defaults = [ "async-trait", "ed25519-compact", "futures", @@ -227,11 +227,15 @@ net = [ #"p2p-nym", ] +p2p-unix = [] + +net = ["net-defaults"] + rpc = [ "async-trait", "httparse", - "net", + "net-defaults", ] system = [ @@ -278,6 +282,14 @@ zk = [ zkas = [ "darkfi-serial", ] + +# Could not get this to work. Complains manifest-key is ignored. +#[target.'cfg(target_family = "unix")'.features] +#net = ["net-defaults", "p2p-unix"] +# +#[target.'cfg(target_family = "windows")'.features] +#net = ["net-defaults"] + # -----END LIBRARY FEATURES----- [patch.crates-io] diff --git a/bin/darkwallet/Cargo.lock b/bin/darkwallet/Cargo.lock index a5d6fb4a75ec..acfc54ce3cbc 100644 --- a/bin/darkwallet/Cargo.lock +++ b/bin/darkwallet/Cargo.lock @@ -3054,7 +3054,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniquad" version = "0.4.7" -source = "git+https://github.com/not-fl3/miniquad#3a5b56399ec446a35bf4a0e855dac969f920d3d4" +source = "git+https://github.com/not-fl3/miniquad#0d4043157531b1972e58d96bcc4d4827d853d036" dependencies = [ "libc", "ndk-sys", @@ -4439,16 +4439,6 @@ dependencies = [ "cfg-if", "cpufeatures", "digest", - "sha1-asm", -] - -[[package]] -name = "sha1-asm" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "286acebaf8b67c1130aedffad26f594eff0c1292389158135327d2e23aed582b" -dependencies = [ - "cc", ] [[package]] diff --git a/bin/darkwallet/Cargo.toml b/bin/darkwallet/Cargo.toml index adb300d07fb4..28cb4032814c 100644 --- a/bin/darkwallet/Cargo.toml +++ b/bin/darkwallet/Cargo.toml @@ -80,6 +80,10 @@ rusqlite = {version = "0.32.1", features = ["bundled"]} tor-dirmgr = {version="0.23.0", features=["static"]} #android-fileopen = {path = "./android-fileopen/"} +[target.'cfg(target_os = "windows")'.dependencies] +# Used by tor-dirmgr +rusqlite = {version = "0.32", features = ["bundled"]} + [package.metadata.android.activity_attributes] "android:exported" = "true" "android:windowSoftInputMode" = "adjustResize" diff --git a/bin/darkwallet/README.win32.md b/bin/darkwallet/README.win32.md new file mode 100644 index 000000000000..031f16a5efcf --- /dev/null +++ b/bin/darkwallet/README.win32.md @@ -0,0 +1,141 @@ +# Windows Build Guide (MSVC) + +Skip the first step if you're already using Windows. + +## Prepare the VM + +You will need qemu and the remote-viewer tool. + +Provision a disk: + +``` +qemu-img create -f raw winblows-raw.disk 100G +``` + +Download the Windows ISO from their website. Use this script to launch QEMU. + +``` +#!/bin/bash + +ISO=Win10_22H2_EnglishInternational_x64v1.iso + +args=( + --cdrom $ISO --boot order=d + + -drive file=winblows-disk.raw,format=raw + + -m 30G -accel kvm -cpu qemu64 + + # We forward 22 to 10022 for SSH + #-net nic -net user,hostname=windowsvm + -net nic -net user,hostname=windowsvm,hostfwd=tcp::10146-:22 + + # This fixes the fucked up mouse + #-device qemu-xhci -device usb-mouse -device usb-tablet + -machine vmport=off + + # Auto-resize display + # -vga qxl + # We use virtio since it allows us the full res size at least + -vga virtio -spice port=30001,disable-ticketing=on + -device virtio-serial -chardev spicevmc,id=vdagent,debug=0,name=vdagent + -device virtserialport,chardev=vdagent,name=com.redhat.spice.0 +) + +qemu-system-x86_64 "${args[@]}" +``` + +There will be no output. Use remote-viewer to attach the display: + +``` +remote-viewer spice://localhost:30001 +``` + +Now install Windows. Then power off Windows. Download the [virtio-win ISO]. +Modify the `ISO=...` line of the script above and relaunch the VM. + +Navigate to the CD drive in the file explorer and install the virtio x64 driver. + +In your browser go to "spice windows guest" and scroll down the webpage. +Download and install "Windows SPICE Guest Tools". + +Relaunch the Windows VM. Adjust your display resolution and fullscreen the VM. + +### (Optional) Enable SSH + +This will enable you to work on Windows from within your host. + +Open Settings -> Apps -> Optional features -> + Add a feature. Search +for "OpenSSH Server" and install it. + +Open Services -> OpenSSH SSH Server. Make "Startup type" Automatic. + +You can now ssh into your windows and use cmd.exe. In the script above, +we forward port 22 to 10146. You can put this in `~/.ssh/config`. + +``` +Host winblows + Hostname localhost + User a + Port 10146 +``` + +You can also make an `/etc/fstab` entry with: + +``` +sshfs#winblows: /mnt/winblows fuse noauto,defaults 0 0 +``` + +Then `mount /mnt/winblows && cd /mnt/winblows/.ssh/` and copy your SSH pubkey +to `authorized_keys`. +Open "This PC", View -> Hidden files, open `C:\ProgramData\ssh\sshd_config` +to disable password login and just use pubkey auth. +Also disable the administrator auth keys setting in there too (bottom 2 lines). +Then restart SSH. + +## Setting Up the Dev Environment + +Install rustup, which will also install Visual Studio. Next, next, finish. +After visual studio, it will then proceed with the rustup install. +Select 2 and enter nightly. + +``` +1) Proceed with standard installation (default - just press enter) +2) Customize installation +3) Cancel installation +>2 + +Default host triple? [x86_64-pc-windows-msvc] +(leave this unchanged) + +Default toolchain? (stable/beta/nightly/none) +nightly + +Profile (which tools and data to install)? (minimal/default/complete) [default] +(leave this unchanged) +``` + +Then proceed with the installation (option 1). + +## Building the DarkFi App + +Go to the [codeberg repo] and select "⋯", then Download ZIP. Unzip the folder +in an accessible place. + +Open cmd and navigate to the folder. Now run `cargo build`. + +``` +C:\Users\a> cd ../../darkfi/bin/darkwallet/ +C:\darkfi\bin\darkwallet> cargo build +``` + +## (Optional) Mesa GL + +This is buggy af software renderer. + +* Setup OpenGL using [this guide](https://thomas.inf3.ch/2019-06-12-opengl-kvm-mesa3d/index.html). + * Download [mesa3d-xxx-release-msvc.7z](https://github.com/pal1000/mesa-dist-win/releases) + and install the default options. + +[virtio-win ISO]: https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso + diff --git a/src/contract/dao/Cargo.toml b/src/contract/dao/Cargo.toml index 9a6bd3738df1..31daf0a7b681 100644 --- a/src/contract/dao/Cargo.toml +++ b/src/contract/dao/Cargo.toml @@ -33,6 +33,7 @@ darkfi-contract-test-harness = {path = "../test-harness"} # so the wasm32-unknown-unknown target is enabled. [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2.8", features = ["custom"] } +darkfi-sdk = { path = "../../sdk", features = ["wasm"] } [features] default = [] diff --git a/src/contract/deployooor/Cargo.toml b/src/contract/deployooor/Cargo.toml index 9df30eceb74b..0cc2401640f2 100644 --- a/src/contract/deployooor/Cargo.toml +++ b/src/contract/deployooor/Cargo.toml @@ -29,6 +29,7 @@ smol = "2.0.2" # so the wasm32-unknown-unknown target is enabled. [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2.8", features = ["custom"] } +darkfi-sdk = { path = "../../sdk", features = ["wasm"] } [features] default = [] diff --git a/src/contract/money/Cargo.toml b/src/contract/money/Cargo.toml index 5365eb36a2a8..e33b49bdd9fc 100644 --- a/src/contract/money/Cargo.toml +++ b/src/contract/money/Cargo.toml @@ -35,6 +35,7 @@ darkfi-contract-test-harness = {path = "../test-harness"} # so the wasm32-unknown-unknown target is enabled. [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2.8", features = ["custom"] } +darkfi-sdk = { path = "../../sdk", features = ["wasm"] } [features] default = [] diff --git a/src/net/p2p.rs b/src/net/p2p.rs index 1bb763f6cf29..e50005135bce 100644 --- a/src/net/p2p.rs +++ b/src/net/p2p.rs @@ -24,11 +24,7 @@ use std::sync::{ use futures::{stream::FuturesUnordered, TryFutureExt}; use futures_rustls::rustls::crypto::{ring, CryptoProvider}; use log::{debug, error, info, warn}; -use smol::{ - fs::{self, unix::PermissionsExt}, - lock::RwLock as AsyncRwLock, - stream::StreamExt, -}; +use smol::{fs, lock::RwLock as AsyncRwLock, stream::StreamExt}; use url::Url; use super::{ @@ -49,6 +45,9 @@ use crate::{ Result, }; +#[cfg(target_family = "unix")] +use smol::fs::unix::PermissionsExt; + /// Atomic pointer to the p2p interface pub type P2pPtr = Arc; @@ -92,6 +91,8 @@ impl P2p { if let Some(ref datastore) = settings.p2p_datastore { let datastore = expand_path(datastore)?; fs::create_dir_all(&datastore).await?; + // Windows only has readonly so don't worry about it + #[cfg(target_family = "unix")] fs::set_permissions(&datastore, PermissionsExt::from_mode(0o700)).await?; } diff --git a/src/net/transport/mod.rs b/src/net/transport/mod.rs index 53b263b628b0..2b9dc8de508b 100644 --- a/src/net/transport/mod.rs +++ b/src/net/transport/mod.rs @@ -16,16 +16,16 @@ * along with this program. If not, see . */ -use std::{ - io::{self, ErrorKind}, - time::Duration, -}; +use std::{io, time::Duration}; use async_trait::async_trait; use log::error; use smol::io::{AsyncRead, AsyncWrite}; use url::Url; +#[cfg(feature = "p2p-unix")] +use std::io::ErrorKind; + /// TLS upgrade mechanism pub(crate) mod tls; @@ -44,6 +44,7 @@ pub(crate) mod tor; pub(crate) mod nym; /// Unix socket transport +#[cfg(feature = "p2p-unix")] pub(crate) mod unix; /// Dialer variants @@ -72,6 +73,7 @@ pub enum DialerVariant { NymTls(nym::NymDialer), /// Unix socket + #[cfg(feature = "p2p-unix")] Unix(unix::UnixDialer), /// SOCKS5 proxy @@ -92,6 +94,7 @@ pub enum ListenerVariant { Tor(tor::TorListener), /// Unix socket + #[cfg(feature = "p2p-unix")] Unix(unix::UnixListener), } @@ -111,6 +114,7 @@ macro_rules! enforce_hostport { }; } +#[cfg(feature = "p2p-unix")] macro_rules! enforce_abspath { ($endpoint:ident) => { if $endpoint.host_str().is_some() || $endpoint.port().is_some() { @@ -179,6 +183,7 @@ impl Dialer { Ok(Self { endpoint, variant }) } + #[cfg(feature = "p2p-unix")] "unix" => { // Build a Unix socket dialer enforce_abspath!(endpoint); @@ -252,6 +257,7 @@ impl Dialer { todo!(); } + #[cfg(feature = "p2p-unix")] DialerVariant::Unix(dialer) => { let path = match self.endpoint.to_file_path() { Ok(v) => v, @@ -312,6 +318,7 @@ impl Listener { Ok(Self { endpoint, variant }) } + #[cfg(feature = "p2p-unix")] "unix" => { enforce_abspath!(endpoint); let variant = unix::UnixListener::new().await?; @@ -351,6 +358,7 @@ impl Listener { Ok(Box::new(l)) } + #[cfg(feature = "p2p-unix")] ListenerVariant::Unix(listener) => { let path = match self.endpoint.to_file_path() { Ok(v) => v, @@ -384,6 +392,7 @@ impl PtStream for arti_client::DataStream {} #[cfg(feature = "p2p-tor")] impl PtStream for futures_rustls::TlsStream {} +#[cfg(feature = "p2p-unix")] impl PtStream for smol::net::unix::UnixStream {} /// Wrapper trait for async listeners diff --git a/src/net/transport/tcp.rs b/src/net/transport/tcp.rs index 3364d2de3e3d..c2fe78756d53 100644 --- a/src/net/transport/tcp.rs +++ b/src/net/transport/tcp.rs @@ -34,6 +34,23 @@ use url::Url; use super::{PtListener, PtStream}; +trait SocketExt { + fn enable_reuse_port(&self) -> io::Result<()>; +} + +impl SocketExt for Socket { + fn enable_reuse_port(&self) -> io::Result<()> { + #[cfg(target_family = "unix")] + self.set_reuse_port(true)?; + + // On Windows SO_REUSEPORT means the same thing as SO_REUSEADDR + #[cfg(target_family = "windows")] + self.set_reuse_address(true)?; + + Ok(()) + } +} + /// TCP Dialer implementation #[derive(Debug, Clone)] pub struct TcpDialer { @@ -63,7 +80,7 @@ impl TcpDialer { socket.set_nodelay(true)?; let keepalive = TcpKeepalive::new().with_time(Duration::from_secs(20)); socket.set_tcp_keepalive(&keepalive)?; - socket.set_reuse_port(true)?; + socket.enable_reuse_port()?; Ok(socket) } @@ -147,7 +164,7 @@ impl TcpListener { socket.set_nodelay(true)?; let keepalive = TcpKeepalive::new().with_time(Duration::from_secs(20)); socket.set_tcp_keepalive(&keepalive)?; - socket.set_reuse_port(true)?; + socket.enable_reuse_port()?; Ok(socket) } diff --git a/src/sdk/Cargo.toml b/src/sdk/Cargo.toml index 02363e4a310e..6b0a874658a0 100644 --- a/src/sdk/Cargo.toml +++ b/src/sdk/Cargo.toml @@ -14,6 +14,7 @@ doctest = false [features] default = [] async = ["darkfi-serial/async"] +wasm = [] [dependencies] # Error handling diff --git a/src/sdk/src/crypto/smt/mod.rs b/src/sdk/src/crypto/smt/mod.rs index 31a9054b732c..cf664bd9c87f 100644 --- a/src/sdk/src/crypto/smt/mod.rs +++ b/src/sdk/src/crypto/smt/mod.rs @@ -75,6 +75,7 @@ mod test; pub mod util; pub use util::Poseidon; +#[cfg(feature = "wasm")] pub mod wasmdb; // Bit size for Fp (and Fq) diff --git a/src/sdk/src/lib.rs b/src/sdk/src/lib.rs index d153d9ebeb80..290d3a441cc8 100644 --- a/src/sdk/src/lib.rs +++ b/src/sdk/src/lib.rs @@ -52,5 +52,6 @@ pub use tx::ContractCall; pub mod util; #[macro_use] +#[cfg(feature = "wasm")] /// WASM API functions pub mod wasm; diff --git a/src/util/path.rs b/src/util/path.rs index d1bbc5e8922c..97c4975829b8 100644 --- a/src/util/path.rs +++ b/src/util/path.rs @@ -18,59 +18,80 @@ use std::{ env, - ffi::{CStr, OsString}, - fs, mem, - os::unix::prelude::OsStringExt, + ffi::OsString, + fs, path::{Path, PathBuf}, - ptr, }; use crate::{Error, Result}; -/// Returns the path to the user's home directory. -/// Use `$HOME`, fallbacks to `libc::getpwuid_r`, otherwise `None`. -pub fn home_dir() -> Option { - env::var_os("HOME") - .and_then(|h| if h.is_empty() { None } else { Some(h) }) - .or_else(|| unsafe { home_fallback() }) - .map(PathBuf::from) -} - -/// Get the home directory from the passwd entry of the current user using -/// `getpwuid_r(3)`. If it manages, returns an `OsString`, otherwise returns `None`. -unsafe fn home_fallback() -> Option { - let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) { - n if n < 0 => 512_usize, - n => n as usize, +#[cfg(target_family = "unix")] +mod home_dir_impl { + use std::{ + env, + ffi::{CStr, OsString}, + mem, + os::unix::prelude::OsStringExt, + path::PathBuf, + ptr, }; - let mut buf = Vec::with_capacity(amt); - let mut passwd: libc::passwd = mem::zeroed(); - let mut result = ptr::null_mut(); - - let r = libc::getpwuid_r( - libc::getuid(), - &mut passwd, - buf.as_mut_ptr(), - buf.capacity(), - &mut result, - ); - - match r { - 0 if !result.is_null() => { - let ptr = passwd.pw_dir as *const _; - let bytes = CStr::from_ptr(ptr).to_bytes(); - if bytes.is_empty() { - return None + /// Returns the path to the user's home directory. + /// Use `$HOME`, fallbacks to `libc::getpwuid_r`, otherwise `None`. + pub fn home_dir() -> Option { + env::var_os("HOME") + .and_then(|h| if h.is_empty() { None } else { Some(h) }) + .or_else(|| unsafe { home_fallback() }) + .map(PathBuf::from) + } + + /// Get the home directory from the passwd entry of the current user using + /// `getpwuid_r(3)`. If it manages, returns an `OsString`, otherwise returns `None`. + unsafe fn home_fallback() -> Option { + let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) { + n if n < 0 => 512_usize, + n => n as usize, + }; + + let mut buf = Vec::with_capacity(amt); + let mut passwd: libc::passwd = mem::zeroed(); + let mut result = ptr::null_mut(); + + let r = libc::getpwuid_r( + libc::getuid(), + &mut passwd, + buf.as_mut_ptr(), + buf.capacity(), + &mut result, + ); + + match r { + 0 if !result.is_null() => { + let ptr = passwd.pw_dir as *const _; + let bytes = CStr::from_ptr(ptr).to_bytes(); + if bytes.is_empty() { + return None + } + + Some(OsStringExt::from_vec(bytes.to_vec())) } - Some(OsStringExt::from_vec(bytes.to_vec())) + _ => None, } + } +} - _ => None, +#[cfg(target_family = "windows")] +mod home_dir_impl { + use std::{env, path::PathBuf}; + + pub fn home_dir() -> Option { + env::var_os("APPDATA").map(PathBuf::from) } } +pub use home_dir_impl::home_dir; + /// Returns `$XDG_CONFIG_HOME`, `$HOME/.config`, or `None`. pub fn config_dir() -> Option { env::var_os("XDG_CONFIG_HOME")