Просмотр исходного кода

various project wide changes to support win32-msvc target.

* Remove sha1 ASM acceleration (who really cares). We could specialize that feature but it's marginal.
* Create net-defaults feature so we can move p2p-unix out of the default feature set.
    * I didn't figure out conditional enabling of p2p-unix though yet. See the Cargo.toml.
      Maybe instead of using a feature, we just enable it for all unix platforms.
    * Move UnixListener behind p2p-unix.
* darkwallet: for win32 use bundled rusqlite (used by tor-dirmgr).
* sdk: add wasm feature to avoid declaring ABI methods with no corresponding impl linked, which causes linker errors for release builds on windows.
* Move unix specific imports and function calls in src/ behind relevant config targets.
* TCP sockets on Windows call set_reuse_address().
* src/util/path.rs relevant home_dir() impls.
darkfi 1 год назад
Родитель
Сommit
119cd41abe

+ 15 - 3
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]

+ 1 - 11
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]]

+ 4 - 0
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"

+ 141 - 0
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
+

+ 1 - 0
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 = []

+ 1 - 0
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 = []

+ 1 - 0
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 = []

+ 6 - 5
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<P2p>;
 
@@ -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?;
         }
 

+ 13 - 4
src/net/transport/mod.rs

@@ -16,16 +16,16 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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<arti_client::DataStream> {}
 
+#[cfg(feature = "p2p-unix")]
 impl PtStream for smol::net::unix::UnixStream {}
 
 /// Wrapper trait for async listeners

+ 19 - 2
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)
     }

+ 1 - 0
src/sdk/Cargo.toml

@@ -14,6 +14,7 @@ doctest = false
 [features]
 default = []
 async = ["darkfi-serial/async"]
+wasm = []
 
 [dependencies]
 # Error handling

+ 1 - 0
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)

+ 1 - 0
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;

+ 60 - 39
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<PathBuf> {
-    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<OsString> {
-    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<PathBuf> {
+        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<OsString> {
+        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<PathBuf> {
+        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<PathBuf> {
     env::var_os("XDG_CONFIG_HOME")