Crash fixes, reorg handling, and sync performance improvements
Rust / Build on macOS-latest (push) Has been cancelled
Rust / Build on ubuntu-16.04 (push) Has been cancelled
Rust / Build on windows-latest (push) Has been cancelled
Rust / Linux ARMv7 (push) Has been cancelled
Rust / Linux ARM64 (push) Has been cancelled
Rust / Build on ubuntu-latest (push) Has been cancelled

- Fix FFI panics with catch_unwind and safe CString construction
- Handle poisoned mutex/RwLock after prior panics instead of crashing
- Fix empty block list panics in clear_blocks and invalidate_block
- Reuse Tokio runtime across block fetch batches to reduce overhead
- Add fetch_blocks_with_runtime for caller-managed runtime lifecycle
- Update branding, dependencies, and checkpoints for DragonX
This commit is contained in:
2026-03-21 03:55:18 -05:00
parent 505fac6b6e
commit a6a80dc224
34 changed files with 14509 additions and 14481 deletions
+88 -88
View File
@@ -1,88 +1,88 @@
name: Rust name: Rust
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
build: build:
name: Build on ${{ matrix.os }} name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-16.04, windows-latest, macOS-latest] os: [ubuntu-16.04, windows-latest, macOS-latest]
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.38.0 toolchain: 1.38.0
override: true override: true
- name: cargo fetch - name: cargo fetch
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: fetch command: fetch
- name: Build - name: Build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --verbose --release --all args: --verbose --release --all
- name: Run tests - name: Run tests
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --verbose --release --all args: --verbose --release --all
- name: Upload ubuntu/macos - name: Upload ubuntu/macos
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu') if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with: with:
name: ${{ matrix.os }}-silentdragonlite-cli name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli path: target/release/silentdragonlite-cli
- name: Upload windows - name: Upload windows
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows') if: contains(matrix.os, 'windows')
with: with:
name: ${{ matrix.os }}-silentdragonlite-cli.exe name: ${{ matrix.os }}-silentdragonlite-cli.exe
path: target/release/silentdragonlite-cli.exe path: target/release/silentdragonlite-cli.exe
linux_arm7: linux_arm7:
name: Linux ARMv7 name: Linux ARMv7
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: armv7-unknown-linux-gnueabihf target: armv7-unknown-linux-gnueabihf
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true use-cross: true
command: build command: build
args: --release --target armv7-unknown-linux-gnueabihf args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload - name: Upload
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: linux_armv7-silentdragonlite-cli name: linux_armv7-silentdragonlite-cli
path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli
linux_aarch64: linux_aarch64:
name: Linux ARM64 name: Linux ARM64
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: aarch64-unknown-linux-gnu target: aarch64-unknown-linux-gnu
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true use-cross: true
command: build command: build
args: --release --target aarch64-unknown-linux-gnu args: --release --target aarch64-unknown-linux-gnu
- name: Upload - name: Upload
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: linux_aarch64-silentdragonlite-cli name: linux_aarch64-silentdragonlite-cli
path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli
+104 -104
View File
@@ -1,104 +1,104 @@
name: Rust name: Rust
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
build: build:
name: Build on ${{ matrix.os }} name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.38.0 toolchain: 1.38.0
override: true override: true
- name: cargo fetch - name: cargo fetch
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: fetch command: fetch
- name: Build - name: Build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --verbose --release --all args: --verbose --release --all
- name: Run tests - name: Run tests
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --verbose --release --all args: --verbose --release --all
- name: Upload ubuntu/macos - name: Upload ubuntu/macos
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu') if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with: with:
<<<<<<< HEAD <<<<<<< HEAD
<<<<<<< HEAD <<<<<<< HEAD
name: ${{ matrix.os }}-silentdragonlite-cli name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli path: target/release/silentdragonlite-cli
======= =======
name: ${{ matrix.os }}-silentdragonlite-cli name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli path: target/release/silentdragonlite-cli
======= =======
name: ${{ matrix.os }}-zecwallet-cli name: ${{ matrix.os }}-zecwallet-cli
path: target/release/zecwallet-cli path: target/release/zecwallet-cli
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94 >>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
- name: Upload windows - name: Upload windows
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows') if: contains(matrix.os, 'windows')
with: with:
<<<<<<< HEAD <<<<<<< HEAD
name: ${{ matrix.os }}-silentdragonlite-cli.exe name: ${{ matrix.os }}-silentdragonlite-cli.exe
path: target/release/silentdragonlite-cli.exe path: target/release/silentdragonlite-cli.exe
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94 >>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
======= =======
name: ${{ matrix.os }}-zecwallet-cli.exe name: ${{ matrix.os }}-zecwallet-cli.exe
path: target/release/zecwallet-cli.exe path: target/release/zecwallet-cli.exe
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94 >>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
linux_arm7: linux_arm7:
name: Linux ARMv7 name: Linux ARMv7
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: armv7-unknown-linux-gnueabihf target: armv7-unknown-linux-gnueabihf
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true use-cross: true
command: build command: build
args: --release --target armv7-unknown-linux-gnueabihf args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload - name: Upload
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: linux_armv7-silentdragonlite-cli name: linux_armv7-silentdragonlite-cli
path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli
linux_aarch64: linux_aarch64:
name: Linux ARM64 name: Linux ARM64
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: aarch64-unknown-linux-gnu target: aarch64-unknown-linux-gnu
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true use-cross: true
command: build command: build
args: --release --target aarch64-unknown-linux-gnu args: --release --target aarch64-unknown-linux-gnu
- name: Upload - name: Upload
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: linux_aarch64-silentdragonlite-cli name: linux_aarch64-silentdragonlite-cli
path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli
+80 -80
View File
@@ -1,80 +1,80 @@
name: Rust name: Rust
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
build: build:
name: Build on ${{ matrix.os }} name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.38.0 toolchain: 1.38.0
override: true override: true
- name: cargo fetch - name: cargo fetch
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: fetch command: fetch
- name: Build - name: Build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --verbose --release --all args: --verbose --release --all
- name: Run tests - name: Run tests
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --verbose --release --all args: --verbose --release --all
- name: Upload - name: Upload
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: ${{ matrix.os }}-zecwallet-cli name: ${{ matrix.os }}-zecwallet-cli
path: target/release/zecwallet-cli path: target/release/zecwallet-cli
linux_arm7: linux_arm7:
name: Linux ARMv7 name: Linux ARMv7
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: armv7-unknown-linux-gnueabihf target: armv7-unknown-linux-gnueabihf
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true use-cross: true
command: build command: build
args: --release --target armv7-unknown-linux-gnueabihf args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload - name: Upload
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: linux_armv7-zecwallet-cli name: linux_armv7-zecwallet-cli
path: target/armv7-unknown-linux-gnueabihf/release/zecwallet-cli path: target/armv7-unknown-linux-gnueabihf/release/zecwallet-cli
linux_aarch64: linux_aarch64:
name: Linux ARM64 name: Linux ARM64
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: aarch64-unknown-linux-gnu target: aarch64-unknown-linux-gnu
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true use-cross: true
command: build command: build
args: --release --target aarch64-unknown-linux-gnu args: --release --target aarch64-unknown-linux-gnu
- name: Upload - name: Upload
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: linux_aarch64-zecwallet-cli name: linux_aarch64-zecwallet-cli
path: target/aarch64-unknown-linux-gnu/release/zecwallet-cli path: target/aarch64-unknown-linux-gnu/release/zecwallet-cli
+93 -93
View File
@@ -1,93 +1,93 @@
name: Rust name: Rust
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
build: build:
name: Build on ${{ matrix.os }} name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.38.0 toolchain: 1.38.0
override: true override: true
- name: cargo fetch - name: cargo fetch
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: fetch command: fetch
- name: Build - name: Build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --verbose --release --all args: --verbose --release --all
- name: Run tests - name: Run tests
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --verbose --release --all args: --verbose --release --all
- name: Upload ubuntu/macos - name: Upload ubuntu/macos
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu') if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with: with:
<<<<<<< HEAD <<<<<<< HEAD
name: ${{ matrix.os }}-silentdragonlite-cli name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli path: target/release/silentdragonlite-cli
======= =======
name: ${{ matrix.os }}-silentdragonlite-cli name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli path: target/release/silentdragonlite-cli
- name: Upload windows - name: Upload windows
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows') if: contains(matrix.os, 'windows')
with: with:
name: ${{ matrix.os }}-silentdragonlite-cli.exe name: ${{ matrix.os }}-silentdragonlite-cli.exe
path: target/release/silentdragonlite-cli.exe path: target/release/silentdragonlite-cli.exe
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94 >>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
linux_arm7: linux_arm7:
name: Linux ARMv7 name: Linux ARMv7
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: armv7-unknown-linux-gnueabihf target: armv7-unknown-linux-gnueabihf
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true use-cross: true
command: build command: build
args: --release --target armv7-unknown-linux-gnueabihf args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload - name: Upload
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: linux_armv7-silentdragonlite-cli name: linux_armv7-silentdragonlite-cli
path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli
linux_aarch64: linux_aarch64:
name: Linux ARM64 name: Linux ARM64
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: aarch64-unknown-linux-gnu target: aarch64-unknown-linux-gnu
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true use-cross: true
command: build command: build
args: --release --target aarch64-unknown-linux-gnu args: --release --target aarch64-unknown-linux-gnu
- name: Upload - name: Upload
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: linux_aarch64-silentdragonlite-cli name: linux_aarch64-silentdragonlite-cli
path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli
+88 -88
View File
@@ -1,88 +1,88 @@
name: Rust name: Rust
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
build: build:
name: Build on ${{ matrix.os }} name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.38.0 toolchain: 1.38.0
override: true override: true
- name: cargo fetch - name: cargo fetch
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: fetch command: fetch
- name: Build - name: Build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --verbose --release --all args: --verbose --release --all
- name: Run tests - name: Run tests
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --verbose --release --all args: --verbose --release --all
- name: Upload ubuntu/macos - name: Upload ubuntu/macos
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu') if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with: with:
name: ${{ matrix.os }}-zecwallet-cli name: ${{ matrix.os }}-zecwallet-cli
path: target/release/zecwallet-cli path: target/release/zecwallet-cli
- name: Upload windows - name: Upload windows
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows') if: contains(matrix.os, 'windows')
with: with:
name: ${{ matrix.os }}-zecwallet-cli.exe name: ${{ matrix.os }}-zecwallet-cli.exe
path: target/release/zecwallet-cli.exe path: target/release/zecwallet-cli.exe
linux_arm7: linux_arm7:
name: Linux ARMv7 name: Linux ARMv7
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: armv7-unknown-linux-gnueabihf target: armv7-unknown-linux-gnueabihf
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true use-cross: true
command: build command: build
args: --release --target armv7-unknown-linux-gnueabihf args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload - name: Upload
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: linux_armv7-zecwallet-cli name: linux_armv7-zecwallet-cli
path: target/armv7-unknown-linux-gnueabihf/release/zecwallet-cli path: target/armv7-unknown-linux-gnueabihf/release/zecwallet-cli
linux_aarch64: linux_aarch64:
name: Linux ARM64 name: Linux ARM64
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: aarch64-unknown-linux-gnu target: aarch64-unknown-linux-gnu
override: true override: true
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: true use-cross: true
command: build command: build
args: --release --target aarch64-unknown-linux-gnu args: --release --target aarch64-unknown-linux-gnu
- name: Upload - name: Upload
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1
with: with:
name: linux_aarch64-zecwallet-cli name: linux_aarch64-zecwallet-cli
path: target/aarch64-unknown-linux-gnu/release/zecwallet-cli path: target/aarch64-unknown-linux-gnu/release/zecwallet-cli
+7 -7
View File
@@ -1,7 +1,7 @@
target/ target/
.vscode/ .vscode/
history.txt history.txt
/.idea/ /.idea/
tarpaulin-report.html tarpaulin-report.html
/log* /log*
silentdragonlite-cli silentdragonlite-cli
Generated
+2883 -2883
View File
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -1,8 +1,8 @@
[workspace] [workspace]
members = [ members = [
"lib", "lib",
"cli", "cli",
] ]
[profile.release] [profile.release]
debug = false debug = false
+23 -23
View File
@@ -1,23 +1,23 @@
.PHONY: format help .PHONY: format help
# Help system from https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html # Help system from https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
.DEFAULT_GOAL := help .DEFAULT_GOAL := help
# Copyright (c) 2019-2024 Jahway603 & The Hush Developers # Copyright (c) 2019-2024 Jahway603 & The Hush Developers
# Released under the GPLv3 # Released under the GPLv3
# #
# DragonX Silentdragonlite-cli Makefile # DragonX Silentdragonlite-cli Makefile
PROJECT_NAME := "silentdragonxlite-cli" PROJECT_NAME := "silentdragonxlite-cli"
help: help:
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
about: ## Display release info about: ## Display release info
printf "DragonX Silentdragonlite-cli Makefile by jahway603\n" printf "DragonX Silentdragonlite-cli Makefile by jahway603\n"
build: ## Build the release build: ## Build the release
./util/build.sh ./util/build.sh
cp `pwd`/target/release/$(PROJECT_NAME) . cp `pwd`/target/release/$(PROJECT_NAME) .
printf "DragonX silentdragonxlite-cli is ready for you\n" printf "DragonX silentdragonxlite-cli is ready for you\n"
clean: ## Clean the repo clean: ## Clean the repo
cargo clean cargo clean
rm $(PROJECT_NAME) rm $(PROJECT_NAME)
+100 -100
View File
@@ -1,100 +1,100 @@
# SilentDragonXLite CLI # SilentDragonXLite CLI
`silentdragonxlite-cli` is a command line SilentDragonXLite light client. To use it, download the latest binary from the releases page and run `./silentdragonxlite-cli` or compile it yourself as documented below. `silentdragonxlite-cli` is a command line SilentDragonXLite light client. To use it, download the latest binary from the releases page and run `./silentdragonxlite-cli` or compile it yourself as documented below.
This will launch the interactive prompt. Type `help` to get a list of commands This will launch the interactive prompt. Type `help` to get a list of commands
## Running in non-interactive mode: ## Running in non-interactive mode:
You can also run `silentdragonxlite-cli` in non-interactive mode by passing the command you want to run as an argument. For example, `silentdragonxlite-cli addresses` will list all wallet addresses and exit. You can also run `silentdragonxlite-cli` in non-interactive mode by passing the command you want to run as an argument. For example, `silentdragonxlite-cli addresses` will list all wallet addresses and exit.
Run `silentdragonxlite-cli help` to see a list of all commands. Run `silentdragonxlite-cli help` to see a list of all commands.
## Privacy ## Privacy
* While all the keys and transaction detection happens on the client, the server can learn what blocks contain your shielded transactions. * While all the keys and transaction detection happens on the client, the server can learn what blocks contain your shielded transactions.
* The server also learns other metadata about you like your ip address etc... * The server also learns other metadata about you like your ip address etc...
* Also remember that t-addresses don't provide any privacy protection. * Also remember that t-addresses don't provide any privacy protection.
## Notes: ## Notes:
* If you want to run your own server, please see [SilentDragonXLite-cli lightwalletd](https://git.hush.is/hush/lightwalletd), and then run `./silentdragonxlite-cli --server http://127.0.0.1:9067`. You might also need to pass `--dangerous` if you are using a self-signed TLS certificate. * If you want to run your own server, please see [SilentDragonXLite-cli lightwalletd](https://git.hush.is/hush/lightwalletd), and then run `./silentdragonxlite-cli --server http://127.0.0.1:9067`. You might also need to pass `--dangerous` if you are using a self-signed TLS certificate.
* The log file is in `~/.silentdragonxlite/silentdragonxlite-cli.debug.log`. Wallet is stored in `~/.silentdragonxlite/silentdragonxlite-cli.dat` * The log file is in `~/.silentdragonxlite/silentdragonxlite-cli.debug.log`. Wallet is stored in `~/.silentdragonxlite/silentdragonxlite-cli.dat`
### Note Management ### Note Management
silentdragonxlite does automatic note and utxo management, which means it doesn't allow you to manually select which address to send outgoing transactions from. It follows these principles: silentdragonxlite does automatic note and utxo management, which means it doesn't allow you to manually select which address to send outgoing transactions from. It follows these principles:
* Defaults to sending shielded transactions, even if you're sending to a transparent address * Defaults to sending shielded transactions, even if you're sending to a transparent address
* Sapling funds need at least 2 confirmations before they can be spent * Sapling funds need at least 2 confirmations before they can be spent
* Can select funds from multiple shielded addresses in the same transaction * Can select funds from multiple shielded addresses in the same transaction
* Will automatically shield your transparent funds at the first opportunity * Will automatically shield your transparent funds at the first opportunity
* When sending an outgoing transaction to a shielded address, silentdragonxlite can decide to use the transaction to additionally shield your transparent funds (i.e., send your transparent funds to your own shielded address in the same transaction) * When sending an outgoing transaction to a shielded address, silentdragonxlite can decide to use the transaction to additionally shield your transparent funds (i.e., send your transparent funds to your own shielded address in the same transaction)
## Compiling from source ## Compiling from source
#### Pre-requisites #### Pre-requisites
* You need Rust and how you install it will depend on your version of Linux. Below are well known rust versions tested on common Linux distributions. * You need Rust and how you install it will depend on your version of Linux. Below are well known rust versions tested on common Linux distributions.
| Linux Version | Rust Version Tested | Command to install | | Linux Version | Rust Version Tested | Command to install |
|---------------|--------|---------------------------| |---------------|--------|---------------------------|
| Ubuntu 18.04 | 1.47.0 | [USE RUSTUP](https://www.rust-lang.org/tools/install) | | Ubuntu 18.04 | 1.47.0 | [USE RUSTUP](https://www.rust-lang.org/tools/install) |
| Ubuntu 20.04 | 1.57.0 | sudo apt install rust-all | | Ubuntu 20.04 | 1.57.0 | sudo apt install rust-all |
| Debian 11 | 1.50.0 | [USE RUSTUP](https://www.rust-lang.org/tools/install) | | Debian 11 | 1.50.0 | [USE RUSTUP](https://www.rust-lang.org/tools/install) |
| Arch Linux | 1.56.0 | pacman -S rustc cargo | | Arch Linux | 1.56.0 | pacman -S rustc cargo |
* Debian 11 comes with a much older rust compiler (1.48.0) and so you want to use rustup with Debian and install at least 1.50.0. * Debian 11 comes with a much older rust compiler (1.48.0) and so you want to use rustup with Debian and install at least 1.50.0.
* If you're using another Linux distro, then consult their package manager for rustc and cargo, but if it's tool old then you want to [use Rustup](https://www.rust-lang.org/tools/install) to install at least 1.50.0. * If you're using another Linux distro, then consult their package manager for rustc and cargo, but if it's tool old then you want to [use Rustup](https://www.rust-lang.org/tools/install) to install at least 1.50.0.
* The build will fail if you do not have `rustfmt` binary, which is included when you use `rustup` but may not be included in via operating system packages. Using `rustup` is recommended * The build will fail if you do not have `rustfmt` binary, which is included when you use `rustup` but may not be included in via operating system packages. Using `rustup` is recommended
To securely install rustup by compiling it yourself: To securely install rustup by compiling it yourself:
``` ```
git clone https://github.com/rust-lang/rustup git clone https://github.com/rust-lang/rustup
cd rustup cd rustup
cargo run --release cargo run --release
``` ```
The above avoids piping the output of curl to bash (bad idea) and avoids using binaries. It will take a few minutes longer but is the better solution. The above avoids piping the output of curl to bash (bad idea) and avoids using binaries. It will take a few minutes longer but is the better solution.
#### The compilation #### The compilation
Run the following commands to compile on your computer. Run the following commands to compile on your computer.
```shell script ```shell script
git clone https://git.hush.is/dragonx/silentdragonxlite-cli git clone https://git.hush.is/dragonx/silentdragonxlite-cli
cd silentdragonxlite-cli cd silentdragonxlite-cli
cargo build --release cargo build --release
./target/release/silentdragonxlite-cli ./target/release/silentdragonxlite-cli
``` ```
#### Or build with make #### Or build with make
Alternatively, you can use the new makefile to build Alternatively, you can use the new makefile to build
```shell script ```shell script
make help make help
make build make build
``` ```
## Options ## Options
Here are some CLI arguments you can pass to `silentdragonxlite-cli`. Please run `silentdragonxlite-cli --help` for the full list. Here are some CLI arguments you can pass to `silentdragonxlite-cli`. Please run `silentdragonxlite-cli --help` for the full list.
* `--server`: Connect to a custom SilentDragonXLite lightwalletd server. * `--server`: Connect to a custom SilentDragonXLite lightwalletd server.
* Example: `./silentdragonxlite-cli --server 127.0.0.1:9067` * Example: `./silentdragonxlite-cli --server 127.0.0.1:9067`
* Example: `./silentdragonxlite-cli --server lite.dragonx.is` * Example: `./silentdragonxlite-cli --server lite.dragonx.is`
* `--seed`: Restore a wallet from a seed phrase. **Note** that this will fail if there is an existing wallet. Delete (or move) any existing wallet to restore from the 24-word seed phrase * `--seed`: Restore a wallet from a seed phrase. **Note** that this will fail if there is an existing wallet. Delete (or move) any existing wallet to restore from the 24-word seed phrase
* Example: `./silentdragonxlite-cli --seed "twenty four words seed phrase"` * Example: `./silentdragonxlite-cli --seed "twenty four words seed phrase"`
* `--recover`: Attempt to recover the seed phrase from a corrupted wallet * `--recover`: Attempt to recover the seed phrase from a corrupted wallet
* `-n, --nosync`: By default, silentdragonxlite-cli will sync the wallet at startup, so use this option to prevent the automatic sync at startup * `-n, --nosync`: By default, silentdragonxlite-cli will sync the wallet at startup, so use this option to prevent the automatic sync at startup
### Support ### Support
For support or other questions, join us on [Telegram](https://dragonx.is/tg) or [file an issue](https://git.hush.is/dragonx/silentdragonxlite-cli/issues). For support or other questions, join us on [Telegram](https://dragonx.is/tg) or [file an issue](https://git.hush.is/dragonx/silentdragonxlite-cli/issues).
## Copyright ## Copyright
Copyright The Hush Developers 2019-2024 Copyright The Hush Developers 2019-2024
## License ## License
GPLv3 or later GPLv3 or later
+18 -18
View File
@@ -1,18 +1,18 @@
[package] [package]
name = "silentdragonxlite-cli" name = "silentdragonxlite-cli"
version = "1.0.0" version = "1.0.0"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
rustyline = "5.0.2" rustyline = "5.0.2"
clap = "2.33" clap = "2.33"
log = "0.4" log = "0.4"
log4rs = "0.8.3" log4rs = "0.8.3"
shellwords = "1.0.0" shellwords = "1.0.0"
json = "0.12.0" json = "0.12.0"
http = "0.2" http = "0.2"
byteorder = "1" byteorder = "1"
tiny-bip39 = "0.6.2" tiny-bip39 = "0.6.2"
silentdragonxlitelib = { path = "../lib/" } silentdragonxlitelib = { path = "../lib/" }
+262 -262
View File
@@ -1,262 +1,262 @@
use std::io::{self}; use std::io::{self};
use std::sync::Arc; use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver}; use std::sync::mpsc::{channel, Sender, Receiver};
use log::{info, error}; use log::{info, error};
use silentdragonxlitelib::{commands, use silentdragonxlitelib::{commands,
lightclient::{LightClient, LightClientConfig}, lightclient::{LightClient, LightClientConfig},
}; };
#[macro_export] #[macro_export]
macro_rules! configure_clapapp { macro_rules! configure_clapapp {
( $freshapp: expr ) => { ( $freshapp: expr ) => {
$freshapp.version("1.0.0") $freshapp.version("1.0.0")
.arg(Arg::with_name("dangerous") .arg(Arg::with_name("dangerous")
.long("dangerous") .long("dangerous")
.help("Disable server TLS certificate verification. Use this if you're running a local lightwalletd with a self-signed certificate. WARNING: This is dangerous, don't use it with a server that is not your own.") .help("Disable server TLS certificate verification. Use this if you're running a local lightwalletd with a self-signed certificate. WARNING: This is dangerous, don't use it with a server that is not your own.")
.takes_value(false)) .takes_value(false))
.arg(Arg::with_name("nosync") .arg(Arg::with_name("nosync")
.help("By default, Silentdragonlite-cli will sync the wallet at startup. Pass --nosync to prevent the automatic sync at startup.") .help("By default, Silentdragonlite-cli will sync the wallet at startup. Pass --nosync to prevent the automatic sync at startup.")
.long("nosync") .long("nosync")
.short("n") .short("n")
.takes_value(false)) .takes_value(false))
.arg(Arg::with_name("recover") .arg(Arg::with_name("recover")
.long("recover") .long("recover")
.help("Attempt to recover the seed from the wallet") .help("Attempt to recover the seed from the wallet")
.takes_value(false)) .takes_value(false))
.arg(Arg::with_name("password") .arg(Arg::with_name("password")
.long("password") .long("password")
.help("When recovering seed, specify a password for the encrypted wallet") .help("When recovering seed, specify a password for the encrypted wallet")
.takes_value(true)) .takes_value(true))
.arg(Arg::with_name("seed") .arg(Arg::with_name("seed")
.short("s") .short("s")
.long("seed") .long("seed")
.value_name("seed_phrase") .value_name("seed_phrase")
.help("Create a new wallet with the given 24-word seed phrase. Will fail if wallet already exists") .help("Create a new wallet with the given 24-word seed phrase. Will fail if wallet already exists")
.takes_value(true)) .takes_value(true))
.arg(Arg::with_name("birthday") .arg(Arg::with_name("birthday")
.long("birthday") .long("birthday")
.value_name("birthday") .value_name("birthday")
.help("Specify wallet birthday when restoring from seed. This is the earlist block height where the wallet has a transaction.") .help("Specify wallet birthday when restoring from seed. This is the earlist block height where the wallet has a transaction.")
.takes_value(true)) .takes_value(true))
.arg(Arg::with_name("server") .arg(Arg::with_name("server")
.long("server") .long("server")
.value_name("server") .value_name("server")
.help("Lightwalletd server to connect to.") .help("Lightwalletd server to connect to.")
.takes_value(true) .takes_value(true)
.default_value(lightclient::DEFAULT_SERVER)) .default_value(lightclient::DEFAULT_SERVER))
.arg(Arg::with_name("COMMAND") .arg(Arg::with_name("COMMAND")
.help("Command to execute. If a command is not specified, Silentdragonlite-cli will start in interactive mode.") .help("Command to execute. If a command is not specified, Silentdragonlite-cli will start in interactive mode.")
.required(false) .required(false)
.index(1)) .index(1))
.arg(Arg::with_name("PARAMS") .arg(Arg::with_name("PARAMS")
.help("Params to execute command with. Run the 'help' command to get usage help.") .help("Params to execute command with. Run the 'help' command to get usage help.")
.required(false) .required(false)
.multiple(true)) .multiple(true))
}; };
} }
/// This function is only tested against Linux. /// This function is only tested against Linux.
pub fn report_permission_error() { pub fn report_permission_error() {
let user = std::env::var("USER").expect( let user = std::env::var("USER").expect(
"Unexpected error reading value of $USER!"); "Unexpected error reading value of $USER!");
let home = std::env::var("HOME").expect( let home = std::env::var("HOME").expect(
"Unexpected error reading value of $HOME!"); "Unexpected error reading value of $HOME!");
let current_executable = std::env::current_exe() let current_executable = std::env::current_exe()
.expect("Unexpected error reporting executable path!"); .expect("Unexpected error reporting executable path!");
eprintln!("USER: {}", user); eprintln!("USER: {}", user);
eprintln!("HOME: {}", home); eprintln!("HOME: {}", home);
eprintln!("Executable: {}", current_executable.display()); eprintln!("Executable: {}", current_executable.display());
if home == "/" { if home == "/" {
eprintln!("User {} must have permission to write to '{}.silentdragonxlite/' .", eprintln!("User {} must have permission to write to '{}.silentdragonxlite/' .",
user, user,
home); home);
} else { } else {
eprintln!("User {} must have permission to write to '{}/.silentdragonxlite/' .", eprintln!("User {} must have permission to write to '{}/.silentdragonxlite/' .",
user, user,
home); home);
} }
} }
pub fn startup(server: http::Uri, dangerous: bool, seed: Option<String>, birthday: u64, first_sync: bool, print_updates: bool) pub fn startup(server: http::Uri, dangerous: bool, seed: Option<String>, birthday: u64, first_sync: bool, print_updates: bool)
-> io::Result<(Sender<(String, Vec<String>)>, Receiver<String>)> { -> io::Result<(Sender<(String, Vec<String>)>, Receiver<String>)> {
// Try to get the configuration // Try to get the configuration
let (config, latest_block_height) = LightClientConfig::create(server.clone(), dangerous)?; let (config, latest_block_height) = LightClientConfig::create(server.clone(), dangerous)?;
let lightclient = match seed { let lightclient = match seed {
Some(phrase) => Arc::new(LightClient::new_from_phrase(phrase, &config, birthday,0, false)?), Some(phrase) => Arc::new(LightClient::new_from_phrase(phrase, &config, birthday,0, false)?),
None => { None => {
if config.wallet_exists() { if config.wallet_exists() {
Arc::new(LightClient::read_from_disk(&config)?) Arc::new(LightClient::read_from_disk(&config)?)
} else { } else {
println!("Creating a new wallet"); println!("Creating a new wallet");
Arc::new(LightClient::new(&config, latest_block_height)?) Arc::new(LightClient::new(&config, latest_block_height)?)
} }
} }
}; };
// Initialize logging // Initialize logging
lightclient.init_logging()?; lightclient.init_logging()?;
// Print startup Messages // Print startup Messages
info!(""); // Blank line info!(""); // Blank line
info!("Starting Silentdragonlite-CLI"); info!("Starting Silentdragonlite-CLI");
info!("Light Client config {:?}", config); info!("Light Client config {:?}", config);
if print_updates { if print_updates {
println!("Lightclient connecting to {}", config.server); println!("Lightclient connecting to {}", config.server);
} }
// At startup, run a sync. // At startup, run a sync.
if first_sync { if first_sync {
let update = lightclient.do_sync(true); let update = lightclient.do_sync(true);
if print_updates { if print_updates {
match update { match update {
Ok(j) => { Ok(j) => {
println!("{}", j.pretty(2)); println!("{}", j.pretty(2));
}, },
Err(e) => println!("{}", e) Err(e) => println!("{}", e)
} }
} }
} }
// Start the command loop // Start the command loop
let (command_tx, resp_rx) = command_loop(lightclient.clone()); let (command_tx, resp_rx) = command_loop(lightclient.clone());
Ok((command_tx, resp_rx)) Ok((command_tx, resp_rx))
} }
pub fn start_interactive(command_tx: Sender<(String, Vec<String>)>, resp_rx: Receiver<String>) { pub fn start_interactive(command_tx: Sender<(String, Vec<String>)>, resp_rx: Receiver<String>) {
// `()` can be used when no completer is required // `()` can be used when no completer is required
let mut rl = rustyline::Editor::<()>::new(); let mut rl = rustyline::Editor::<()>::new();
println!("Ready!"); println!("Ready!");
let send_command = |cmd: String, args: Vec<String>| -> String { let send_command = |cmd: String, args: Vec<String>| -> String {
command_tx.send((cmd.clone(), args)).unwrap(); command_tx.send((cmd.clone(), args)).unwrap();
match resp_rx.recv() { match resp_rx.recv() {
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
let e = format!("Error executing command {}: {}", cmd, e); let e = format!("Error executing command {}: {}", cmd, e);
eprintln!("{}", e); eprintln!("{}", e);
error!("{}", e); error!("{}", e);
return "".to_string() return "".to_string()
} }
} }
}; };
let info = send_command("info".to_string(), vec![]); let info = send_command("info".to_string(), vec![]);
let chain_name = json::parse(&info).unwrap()["chain_name"].as_str().unwrap().to_string(); let chain_name = json::parse(&info).unwrap()["chain_name"].as_str().unwrap().to_string();
loop { loop {
// Read the height first // Read the height first
let height = json::parse(&send_command("height".to_string(), vec!["false".to_string()])).unwrap()["height"].as_i64().unwrap(); let height = json::parse(&send_command("height".to_string(), vec!["false".to_string()])).unwrap()["height"].as_i64().unwrap();
let readline = rl.readline(&format!("({}) Block:{} (type 'help') >> ", let readline = rl.readline(&format!("({}) Block:{} (type 'help') >> ",
chain_name, height)); chain_name, height));
match readline { match readline {
Ok(line) => { Ok(line) => {
rl.add_history_entry(line.as_str()); rl.add_history_entry(line.as_str());
// Parse command line arguments // Parse command line arguments
let mut cmd_args = match shellwords::split(&line) { let mut cmd_args = match shellwords::split(&line) {
Ok(args) => args, Ok(args) => args,
Err(_) => { Err(_) => {
println!("Mismatched Quotes"); println!("Mismatched Quotes");
continue; continue;
} }
}; };
if cmd_args.is_empty() { if cmd_args.is_empty() {
continue; continue;
} }
let cmd = cmd_args.remove(0); let cmd = cmd_args.remove(0);
let args: Vec<String> = cmd_args; let args: Vec<String> = cmd_args;
println!("{}", send_command(cmd, args)); println!("{}", send_command(cmd, args));
// Special check for Quit command. // Special check for Quit command.
if line == "quit" { if line == "quit" {
break; break;
} }
}, },
Err(rustyline::error::ReadlineError::Interrupted) => { Err(rustyline::error::ReadlineError::Interrupted) => {
println!("CTRL-C"); println!("CTRL-C");
info!("CTRL-C"); info!("CTRL-C");
println!("{}", send_command("save".to_string(), vec![])); println!("{}", send_command("save".to_string(), vec![]));
break break
}, },
Err(rustyline::error::ReadlineError::Eof) => { Err(rustyline::error::ReadlineError::Eof) => {
println!("CTRL-D"); println!("CTRL-D");
info!("CTRL-D"); info!("CTRL-D");
println!("{}", send_command("save".to_string(), vec![])); println!("{}", send_command("save".to_string(), vec![]));
break break
}, },
Err(err) => { Err(err) => {
println!("Error: {:?}", err); println!("Error: {:?}", err);
break break
} }
} }
} }
} }
pub fn command_loop(lightclient: Arc<LightClient>) -> (Sender<(String, Vec<String>)>, Receiver<String>) { pub fn command_loop(lightclient: Arc<LightClient>) -> (Sender<(String, Vec<String>)>, Receiver<String>) {
let (command_tx, command_rx) = channel::<(String, Vec<String>)>(); let (command_tx, command_rx) = channel::<(String, Vec<String>)>();
let (resp_tx, resp_rx) = channel::<String>(); let (resp_tx, resp_rx) = channel::<String>();
let lc = lightclient.clone(); let lc = lightclient.clone();
std::thread::spawn(move || { std::thread::spawn(move || {
//start mempool_monitor //start mempool_monitor
match LightClient::start_mempool_monitor(lc.clone()) { match LightClient::start_mempool_monitor(lc.clone()) {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
error!("Error starting mempool: {:?}", e); error!("Error starting mempool: {:?}", e);
} }
} }
loop { loop {
match command_rx.recv_timeout(std::time::Duration::from_secs(5 * 60)) { match command_rx.recv_timeout(std::time::Duration::from_secs(5 * 60)) {
Ok((cmd, args)) => { Ok((cmd, args)) => {
let args = args.iter().map(|s| s.as_ref()).collect(); let args = args.iter().map(|s| s.as_ref()).collect();
let cmd_response = commands::do_user_command(&cmd, &args, lc.as_ref()); let cmd_response = commands::do_user_command(&cmd, &args, lc.as_ref());
resp_tx.send(cmd_response).unwrap(); resp_tx.send(cmd_response).unwrap();
if cmd == "quit" { if cmd == "quit" {
info!("Quit"); info!("Quit");
break; break;
} }
}, },
Err(_) => { Err(_) => {
// Timeout. Do a sync to keep the wallet up-to-date. False to whether to print updates on the console // Timeout. Do a sync to keep the wallet up-to-date. False to whether to print updates on the console
info!("Timeout, doing a sync"); info!("Timeout, doing a sync");
match lc.do_sync(false) { match lc.do_sync(false) {
Ok(_) => {}, Ok(_) => {},
Err(e) => {error!("{}", e)} Err(e) => {error!("{}", e)}
} }
} }
} }
} }
}); });
(command_tx, resp_rx) (command_tx, resp_rx)
} }
pub fn attempt_recover_seed(password: Option<String>) { pub fn attempt_recover_seed(password: Option<String>) {
// Create a Light Client Config in an attempt to recover the file. // Create a Light Client Config in an attempt to recover the file.
let config = LightClientConfig { let config = LightClientConfig {
server: "0.0.0.0:0".parse().unwrap(), server: "0.0.0.0:0".parse().unwrap(),
chain_name: "main".to_string(), chain_name: "main".to_string(),
sapling_activation_height: 0, sapling_activation_height: 0,
consensus_branch_id: "000000".to_string(), consensus_branch_id: "000000".to_string(),
anchor_offset: 0, anchor_offset: 0,
no_cert_verification: false, no_cert_verification: false,
data_dir: None, data_dir: None,
}; };
match LightClient::attempt_recover_seed(&config, password) { match LightClient::attempt_recover_seed(&config, password) {
Ok(_seed) => println!("Recovered seed "), Ok(_seed) => println!("Recovered seed "),
Err(e) => eprintln!("Failed to recover seed. Error: {}", e) Err(e) => eprintln!("Failed to recover seed. Error: {}", e)
}; };
} }
+93 -93
View File
@@ -1,93 +1,93 @@
use silentdragonxlitelib::lightclient::{self, LightClientConfig}; use silentdragonxlitelib::lightclient::{self, LightClientConfig};
use silentdragonxlite_cli::{configure_clapapp, use silentdragonxlite_cli::{configure_clapapp,
report_permission_error, report_permission_error,
startup, startup,
start_interactive, start_interactive,
attempt_recover_seed}; attempt_recover_seed};
//version::VERSION //version::VERSION
use log::error; use log::error;
pub fn main() { pub fn main() {
// Get command line arguments // Get command line arguments
use clap::{App, Arg}; use clap::{App, Arg};
let fresh_app = App::new("SilentDragonXLite CLI"); let fresh_app = App::new("SilentDragonXLite CLI");
let configured_app = configure_clapapp!(fresh_app); let configured_app = configure_clapapp!(fresh_app);
let matches = configured_app.get_matches(); let matches = configured_app.get_matches();
if matches.is_present("recover") { if matches.is_present("recover") {
// Create a Light Client Config in an attempt to recover the file. // Create a Light Client Config in an attempt to recover the file.
attempt_recover_seed(matches.value_of("password").map(|s| s.to_string())); attempt_recover_seed(matches.value_of("password").map(|s| s.to_string()));
return; return;
} }
let command = matches.value_of("COMMAND"); let command = matches.value_of("COMMAND");
let params = matches.values_of("PARAMS").map(|v| v.collect()).or(Some(vec![])).unwrap(); let params = matches.values_of("PARAMS").map(|v| v.collect()).or(Some(vec![])).unwrap();
let maybe_server = matches.value_of("server").map(|s| s.to_string()); let maybe_server = matches.value_of("server").map(|s| s.to_string());
let seed = matches.value_of("seed").map(|s| s.to_string()); let seed = matches.value_of("seed").map(|s| s.to_string());
let maybe_birthday = matches.value_of("birthday"); let maybe_birthday = matches.value_of("birthday");
if seed.is_some() && maybe_birthday.is_none() { if seed.is_some() && maybe_birthday.is_none() {
eprintln!("ERROR!"); eprintln!("ERROR!");
eprintln!("Please specify the wallet birthday (eg. '--birthday 600000') to restore from seed."); eprintln!("Please specify the wallet birthday (eg. '--birthday 600000') to restore from seed.");
eprintln!("This should be the block height where the wallet was created. If you don't remember the block height, you can pass '--birthday 0' to scan from the start of the blockchain."); eprintln!("This should be the block height where the wallet was created. If you don't remember the block height, you can pass '--birthday 0' to scan from the start of the blockchain.");
return; return;
} }
let birthday = match maybe_birthday.unwrap_or("0").parse::<u64>() { let birthday = match maybe_birthday.unwrap_or("0").parse::<u64>() {
Ok(b) => b, Ok(b) => b,
Err(e) => { Err(e) => {
eprintln!("Couldn't parse birthday. This should be a block number. Error={}", e); eprintln!("Couldn't parse birthday. This should be a block number. Error={}", e);
return; return;
} }
}; };
let server = LightClientConfig::get_server_or_default(maybe_server); let server = LightClientConfig::get_server_or_default(maybe_server);
// Test to make sure the server has all of scheme, host and port // Test to make sure the server has all of scheme, host and port
if server.scheme_str().is_none() || server.host().is_none() || server.port().is_none() { if server.scheme_str().is_none() || server.host().is_none() || server.port().is_none() {
eprintln!("Please provide the --server parameter as [scheme]://[host]:[port].\nYou provided: {}", server); eprintln!("Please provide the --server parameter as [scheme]://[host]:[port].\nYou provided: {}", server);
return; return;
} }
let dangerous = matches.is_present("dangerous"); let dangerous = matches.is_present("dangerous");
let nosync = matches.is_present("nosync"); let nosync = matches.is_present("nosync");
let (command_tx, resp_rx) = match startup(server, dangerous, seed, birthday, !nosync, command.is_none()) { let (command_tx, resp_rx) = match startup(server, dangerous, seed, birthday, !nosync, command.is_none()) {
Ok(c) => c, Ok(c) => c,
Err(e) => { Err(e) => {
let emsg = format!("Error during startup:{}\nIf you repeatedly run into this issue, you might have to restore your wallet from your seed phrase.", e); let emsg = format!("Error during startup:{}\nIf you repeatedly run into this issue, you might have to restore your wallet from your seed phrase.", e);
eprintln!("{}", emsg); eprintln!("{}", emsg);
error!("{}", emsg); error!("{}", emsg);
if cfg!(target_os = "unix" ) { if cfg!(target_os = "unix" ) {
match e.raw_os_error() { match e.raw_os_error() {
Some(13) => report_permission_error(), Some(13) => report_permission_error(),
_ => {}, _ => {},
} }
}; };
return; return;
} }
}; };
if command.is_none() { if command.is_none() {
start_interactive(command_tx, resp_rx); start_interactive(command_tx, resp_rx);
} else { } else {
command_tx.send( command_tx.send(
(command.unwrap().to_string(), (command.unwrap().to_string(),
params.iter().map(|s| s.to_string()).collect::<Vec<String>>())) params.iter().map(|s| s.to_string()).collect::<Vec<String>>()))
.unwrap(); .unwrap();
match resp_rx.recv() { match resp_rx.recv() {
Ok(s) => println!("{}", s), Ok(s) => println!("{}", s),
Err(e) => { Err(e) => {
let e = format!("Error executing command {}: {}", command.unwrap(), e); let e = format!("Error executing command {}: {}", command.unwrap(), e);
eprintln!("{}", e); eprintln!("{}", e);
error!("{}", e); error!("{}", e);
} }
} }
// Save before exit // Save before exit
command_tx.send(("save".to_string(), vec![])).unwrap(); command_tx.send(("save".to_string(), vec![])).unwrap();
resp_rx.recv().unwrap(); resp_rx.recv().unwrap();
} }
} }
+1 -1
View File
@@ -1 +1 @@
pub const VERSION:&str = "1.1.2"; pub const VERSION:&str = "1.1.2";
+43 -43
View File
@@ -1,43 +1,43 @@
FROM ubuntu:16.04 FROM ubuntu:16.04
LABEL Description="Rust compile env for Linux + Windows (cross)" LABEL Description="Rust compile env for Linux + Windows (cross)"
RUN apt update RUN apt update
RUN apt install -y build-essential mingw-w64 gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf curl vim wget RUN apt install -y build-essential mingw-w64 gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf curl vim wget
# Get Rust # Get Rust
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y RUN curl https://sh.rustup.rs -sSf | bash -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}" ENV PATH="/root/.cargo/bin:${PATH}"
RUN rustup target add x86_64-pc-windows-gnu RUN rustup target add x86_64-pc-windows-gnu
RUN rustup target add aarch64-unknown-linux-gnu RUN rustup target add aarch64-unknown-linux-gnu
RUN rustup target add armv7-unknown-linux-gnueabihf RUN rustup target add armv7-unknown-linux-gnueabihf
# Append the linker to the cargo config for Windows cross compile # Append the linker to the cargo config for Windows cross compile
RUN echo "[target.x86_64-pc-windows-gnu]" >> /root/.cargo/config && \ RUN echo "[target.x86_64-pc-windows-gnu]" >> /root/.cargo/config && \
echo "linker = '/usr/bin/x86_64-w64-mingw32-gcc'" >> /root/.cargo/config echo "linker = '/usr/bin/x86_64-w64-mingw32-gcc'" >> /root/.cargo/config
RUN echo "[target.aarch64-unknown-linux-gnu]" >> /root/.cargo/config && \ RUN echo "[target.aarch64-unknown-linux-gnu]" >> /root/.cargo/config && \
echo "linker = '/usr/bin/aarch64-linux-gnu-gcc'" >> /root/.cargo/config echo "linker = '/usr/bin/aarch64-linux-gnu-gcc'" >> /root/.cargo/config
RUN echo "[target.armv7-unknown-linux-gnueabihf]" >> /root/.cargo/config && \ RUN echo "[target.armv7-unknown-linux-gnueabihf]" >> /root/.cargo/config && \
echo "linker = '/usr/bin/arm-linux-gnueabihf-gcc'" >> /root/.cargo/config echo "linker = '/usr/bin/arm-linux-gnueabihf-gcc'" >> /root/.cargo/config
ENV CC_x86_64_unknown_linux_musl="gcc" ENV CC_x86_64_unknown_linux_musl="gcc"
ENV CC_aarch64_unknown_linux_gnu="aarch64-linux-gnu-gcc" ENV CC_aarch64_unknown_linux_gnu="aarch64-linux-gnu-gcc"
ENV CC_armv7_unknown_linux_gnueabhihf="arm-linux-gnueabihf-gcc" ENV CC_armv7_unknown_linux_gnueabhihf="arm-linux-gnueabihf-gcc"
# This is a bug fix for the windows cross compiler for Rust. # This is a bug fix for the windows cross compiler for Rust.
RUN cp /usr/x86_64-w64-mingw32/lib/crt2.o /root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/crt2.o RUN cp /usr/x86_64-w64-mingw32/lib/crt2.o /root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/crt2.o
# For windows cross compilation, use a pre-build binary. Remember to set the # For windows cross compilation, use a pre-build binary. Remember to set the
# SODIUM_LIB_DIR for windows cross compilation # SODIUM_LIB_DIR for windows cross compilation
RUN cd /opt && wget https://download.libsodium.org/libsodium/releases/libsodium-1.0.17-mingw.tar.gz && \ RUN cd /opt && wget https://download.libsodium.org/libsodium/releases/libsodium-1.0.17-mingw.tar.gz && \
tar xvf libsodium-1.0.17-mingw.tar.gz tar xvf libsodium-1.0.17-mingw.tar.gz
RUN apt install -y git RUN apt install -y git
# Cargo fetch the dependencies so we don't download them over and over again # Cargo fetch the dependencies so we don't download them over and over again
RUN cd /tmp && git clone https://github.com/adityapk00/silentdragonlite-light-cli.git && \ RUN cd /tmp && git clone https://github.com/adityapk00/silentdragonlite-light-cli.git && \
cd silentdragonlite-light-cli && \ cd silentdragonlite-light-cli && \
cargo fetch && \ cargo fetch && \
cd /tmp && rm -rf silentdragonlite-light-cli cd /tmp && rm -rf silentdragonlite-light-cli
+80 -80
View File
@@ -1,80 +1,80 @@
[package] [package]
name = "silentdragonxlitelib" name = "silentdragonxlitelib"
version = "0.1.0" version = "0.1.0"
edition = "2018" edition = "2018"
[features] [features]
default = ["embed_params"] default = ["embed_params"]
embed_params = [] embed_params = []
[dependencies] [dependencies]
base58 = "0.1.0" base58 = "0.1.0"
bs58 = { version = "0.2", features = ["check"] } bs58 = { version = "0.2", features = ["check"] }
log = "0.4" log = "0.4"
log4rs = "0.8.3" log4rs = "0.8.3"
dirs = "2.0.2" dirs = "2.0.2"
http = "0.2" http = "0.2"
hex = "0.3" hex = "0.3"
protobuf = "2" protobuf = "2"
byteorder = "1" byteorder = "1"
json = "0.12.0" json = "0.12.0"
tiny-bip39 = "0.6.2" tiny-bip39 = "0.6.2"
secp256k1 = "=0.15.0" secp256k1 = "=0.15.0"
sha2 = "0.8.0" sha2 = "0.8.0"
ripemd160 = "0.8.0" ripemd160 = "0.8.0"
lazy_static = "1.2.0" lazy_static = "1.2.0"
rust-embed = { version = "5.1.0", features = ["debug-embed"] } rust-embed = { version = "5.1.0", features = ["debug-embed"] }
rand = "0.7.2" rand = "0.7.2"
sodiumoxide = "0.2.5" sodiumoxide = "0.2.5"
ring = "0.16.9" ring = "0.16.9"
libflate = "0.1" libflate = "0.1"
subtle = "2" subtle = "2"
threadpool = "1.8.0" threadpool = "1.8.0"
num_cpus = "1.13.0" num_cpus = "1.13.0"
tonic = { version = "0.1.1", features = ["tls", "tls-roots"] } tonic = { version = "0.1.1", features = ["tls", "tls-roots"] }
bytes = "0.4" bytes = "0.4"
prost = "0.6" prost = "0.6"
prost-types = "0.6" prost-types = "0.6"
tokio = { version = "0.2", features = ["rt-threaded", "time", "stream", "fs", "macros", "uds", "full"] } tokio = { version = "0.2", features = ["rt-threaded", "time", "stream", "fs", "macros", "uds", "full"] }
tokio-rustls = { version = "0.12.1", features = ["dangerous_configuration"] } tokio-rustls = { version = "0.12.1", features = ["dangerous_configuration"] }
webpki = "0.21.0" webpki = "0.21.0"
webpki-roots = "0.18.0" webpki-roots = "0.18.0"
[dependencies.bellman] [dependencies.bellman]
git = "https://git.hush.is/hush/librustzcash.git" git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b" rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false default-features = false
features = ["groth16"] features = ["groth16"]
[dependencies.pairing] [dependencies.pairing]
git = "https://git.hush.is/hush/librustzcash.git" git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b" rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
[dependencies.zcash_client_backend] [dependencies.zcash_client_backend]
git = "https://git.hush.is/hush/librustzcash.git" git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b" rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false default-features = false
[dependencies.zcash_primitives] [dependencies.zcash_primitives]
git = "https://git.hush.is/hush/librustzcash.git" git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b" rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false default-features = false
features = ["transparent-inputs"] features = ["transparent-inputs"]
[dependencies.zcash_proofs] [dependencies.zcash_proofs]
git = "https://git.hush.is/hush/librustzcash.git" git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b" rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false default-features = false
[dependencies.ff] [dependencies.ff]
git = "https://git.hush.is/hush/librustzcash.git" git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b" rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
features = ["ff_derive"] features = ["ff_derive"]
[build-dependencies] [build-dependencies]
tonic-build = "0.1.1" tonic-build = "0.1.1"
[dev-dependencies] [dev-dependencies]
tempdir = "0.3.7" tempdir = "0.3.7"
+13 -13
View File
@@ -1,13 +1,13 @@
// Copyright The Hush Developers 2019-2022 // Copyright The Hush Developers 2019-2022
// Released under the GPLv3 // Released under the GPLv3
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::configure() tonic_build::configure()
.build_server(false) .build_server(false)
.compile( .compile(
&["proto/service.proto", "proto/compact_formats.proto"], &["proto/service.proto", "proto/compact_formats.proto"],
&["proto"], &["proto"],
)?; )?;
println!("cargo:rerun-if-changed=proto/service.proto"); println!("cargo:rerun-if-changed=proto/service.proto");
Ok(()) Ok(())
} }
+65 -65
View File
@@ -1,65 +1,65 @@
syntax = "proto3"; syntax = "proto3";
package cash.z.wallet.sdk.rpc; package cash.z.wallet.sdk.rpc;
option go_package = "lightwalletd/walletrpc"; option go_package = "lightwalletd/walletrpc";
option swift_prefix = ""; option swift_prefix = "";
// Remember that proto3 fields are all optional. A field that is not present will be set to its zero value. // Remember that proto3 fields are all optional. A field that is not present will be set to its zero value.
// bytes fields of hashes are in canonical little-endian format. // bytes fields of hashes are in canonical little-endian format.
// CompactBlock is a packaging of ONLY the data from a block that's needed to: // CompactBlock is a packaging of ONLY the data from a block that's needed to:
// 1. Detect a payment to your shielded Sapling address // 1. Detect a payment to your shielded Sapling address
// 2. Detect a spend of your shielded Sapling notes // 2. Detect a spend of your shielded Sapling notes
// 3. Update your witnesses to generate new Sapling spend proofs. // 3. Update your witnesses to generate new Sapling spend proofs.
message CompactBlock { message CompactBlock {
uint32 protoVersion = 1; // the version of this wire format, for storage uint32 protoVersion = 1; // the version of this wire format, for storage
uint64 height = 2; // the height of this block uint64 height = 2; // the height of this block
bytes hash = 3; // the ID (hash) of this block, same as in block explorers bytes hash = 3; // the ID (hash) of this block, same as in block explorers
bytes prevHash = 4; // the ID (hash) of this block's predecessor bytes prevHash = 4; // the ID (hash) of this block's predecessor
uint32 time = 5; // Unix epoch time when the block was mined uint32 time = 5; // Unix epoch time when the block was mined
bytes header = 6; // (hash, prevHash, and time) OR (full header) bytes header = 6; // (hash, prevHash, and time) OR (full header)
repeated CompactTx vtx = 7; // compact transactions from this block repeated CompactTx vtx = 7; // compact transactions from this block
} }
message CompactTx { message CompactTx {
// Index and hash will allow the receiver to call out to chain // Index and hash will allow the receiver to call out to chain
// explorers or other data structures to retrieve more information // explorers or other data structures to retrieve more information
// about this transaction. // about this transaction.
uint64 index = 1; // the index within the full block uint64 index = 1; // the index within the full block
bytes hash = 2; // the ID (hash) of this transaction, same as in block explorers bytes hash = 2; // the ID (hash) of this transaction, same as in block explorers
// The transaction fee: present if server can provide. In the case of a // The transaction fee: present if server can provide. In the case of a
// stateless server and a transaction with transparent inputs, this will be // stateless server and a transaction with transparent inputs, this will be
// unset because the calculation requires reference to prior transactions. // unset because the calculation requires reference to prior transactions.
// in a pure-Sapling context, the fee will be calculable as: // in a pure-Sapling context, the fee will be calculable as:
// valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut)) // valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut))
uint32 fee = 3; uint32 fee = 3;
repeated CompactSaplingSpend spends = 4; repeated CompactSaplingSpend spends = 4;
repeated CompactSaplingOutput outputs = 5; repeated CompactSaplingOutput outputs = 5;
} }
// CompactSaplingSpend is a Sapling Spend Description as described in 7.3 of the Zcash // CompactSaplingSpend is a Sapling Spend Description as described in 7.3 of the Zcash
// protocol specification. // protocol specification.
message CompactSaplingSpend { message CompactSaplingSpend {
bytes nf = 1; // nullifier (see the Zcash protocol specification) bytes nf = 1; // nullifier (see the Zcash protocol specification)
} }
// output is a Sapling Output Description as described in section 7.4 of the // output is a Sapling Output Description as described in section 7.4 of the
// Zcash protocol spec. Total size is 948. // Zcash protocol spec. Total size is 948.
message CompactSaplingOutput { message CompactSaplingOutput {
bytes cmu = 1; // note commitment u-coordinate bytes cmu = 1; // note commitment u-coordinate
bytes epk = 2; // ephemeral public key bytes epk = 2; // ephemeral public key
bytes ciphertext = 3; // first 52 bytes of ciphertext bytes ciphertext = 3; // first 52 bytes of ciphertext
} }
/* /*
message CompactSpend { message CompactSpend {
bytes nf = 1; // nullifier (see the Zcash protocol specification) bytes nf = 1; // nullifier (see the Zcash protocol specification)
} }
message CompactOutput { message CompactOutput {
bytes cmu = 1; // note commitment u-coordinate bytes cmu = 1; // note commitment u-coordinate
bytes epk = 2; // ephemeral public key bytes epk = 2; // ephemeral public key
bytes ciphertext = 3; // first 52 bytes of ciphertext bytes ciphertext = 3; // first 52 bytes of ciphertext
} }
*/ */
+169 -169
View File
@@ -1,170 +1,170 @@
syntax = "proto3"; syntax = "proto3";
package cash.z.wallet.sdk.rpc; package cash.z.wallet.sdk.rpc;
option go_package = "lightwalletd/walletrpc"; option go_package = "lightwalletd/walletrpc";
option swift_prefix = ""; option swift_prefix = "";
import "compact_formats.proto"; import "compact_formats.proto";
// A BlockID message contains identifiers to select a block: a height or a // A BlockID message contains identifiers to select a block: a height or a
// hash. If the hash is present it takes precedence. // hash. If the hash is present it takes precedence.
message BlockID { message BlockID {
uint64 height = 1; uint64 height = 1;
bytes hash = 2; bytes hash = 2;
} }
// BlockRange technically allows ranging from hash to hash etc but this is not // BlockRange technically allows ranging from hash to hash etc but this is not
// currently intended for support, though there is no reason you couldn't do // currently intended for support, though there is no reason you couldn't do
// it. Further permutations are left as an exercise. // it. Further permutations are left as an exercise.
message BlockRange { message BlockRange {
BlockID start = 1; BlockID start = 1;
BlockID end = 2; BlockID end = 2;
} }
// A TxFilter contains the information needed to identify a particular // A TxFilter contains the information needed to identify a particular
// transaction: either a block and an index, or a direct transaction hash. // transaction: either a block and an index, or a direct transaction hash.
message TxFilter { message TxFilter {
BlockID block = 1; BlockID block = 1;
uint64 index = 2; uint64 index = 2;
bytes hash = 3; bytes hash = 3;
} }
// RawTransaction contains the complete transaction data. It also optionally includes // RawTransaction contains the complete transaction data. It also optionally includes
// the block height in which the transaction was included // the block height in which the transaction was included
message RawTransaction { message RawTransaction {
bytes data = 1; bytes data = 1;
uint64 height = 2; uint64 height = 2;
} }
message SendResponse { message SendResponse {
int32 errorCode = 1; int32 errorCode = 1;
string errorMessage = 2; string errorMessage = 2;
} }
// Empty placeholder. Someday we may want to specify e.g. a particular chain fork. // Empty placeholder. Someday we may want to specify e.g. a particular chain fork.
message ChainSpec {} message ChainSpec {}
message Empty {} message Empty {}
message LightdInfo { message LightdInfo {
string version = 1; string version = 1;
string vendor = 2; string vendor = 2;
bool taddrSupport = 3; bool taddrSupport = 3;
string chainName = 4; string chainName = 4;
uint64 saplingActivationHeight = 5; uint64 saplingActivationHeight = 5;
string consensusBranchId = 6; // This should really be u32 or []byte, but string for readability string consensusBranchId = 6; // This should really be u32 or []byte, but string for readability
uint64 blockHeight = 7; uint64 blockHeight = 7;
uint64 difficulty = 8; uint64 difficulty = 8;
uint64 longestchain = 9; uint64 longestchain = 9;
uint64 notarized = 10; uint64 notarized = 10;
} }
message Coinsupply { message Coinsupply {
string result = 1; string result = 1;
string coin = 2; string coin = 2;
uint64 height = 3; uint64 height = 3;
uint64 supply = 4; uint64 supply = 4;
uint64 zfunds = 5; uint64 zfunds = 5;
uint64 total = 6; uint64 total = 6;
} }
message TransparentAddress { message TransparentAddress {
string address = 1; string address = 1;
} }
message TransparentAddressBlockFilter { message TransparentAddressBlockFilter {
string address = 1; string address = 1;
BlockRange range = 2; BlockRange range = 2;
} }
message Address { message Address {
string address = 1; string address = 1;
} }
message AddressList { message AddressList {
repeated string addresses = 1; repeated string addresses = 1;
} }
message Balance { message Balance {
int64 valueZat = 1; int64 valueZat = 1;
} }
message Exclude { message Exclude {
repeated bytes txid = 1; repeated bytes txid = 1;
} }
// The TreeState is derived from the Hush getblockmerkletree rpc. // The TreeState is derived from the Hush getblockmerkletree rpc.
// https://faq.hush.is/rpc/getblockmerkletree.html // https://faq.hush.is/rpc/getblockmerkletree.html
message TreeState { message TreeState {
string network = 1; // "main" or "test" string network = 1; // "main" or "test"
uint64 height = 2; // block height uint64 height = 2; // block height
string hash = 3; // block id string hash = 3; // block id
uint32 time = 4; // Unix epoch time when the block was mined uint32 time = 4; // Unix epoch time when the block was mined
string saplingTree = 5; // sapling commitment tree state string saplingTree = 5; // sapling commitment tree state
} }
// Results are sorted by height, which makes it easy to issue another // Results are sorted by height, which makes it easy to issue another
// request that picks up from where the previous left off. // request that picks up from where the previous left off.
message GetAddressUtxosArg { message GetAddressUtxosArg {
repeated string addresses = 1; repeated string addresses = 1;
uint64 startHeight = 2; uint64 startHeight = 2;
uint32 maxEntries = 3; // zero means unlimited uint32 maxEntries = 3; // zero means unlimited
} }
message GetAddressUtxosReply { message GetAddressUtxosReply {
string address = 6; string address = 6;
bytes txid = 1; bytes txid = 1;
int32 index = 2; int32 index = 2;
bytes script = 3; bytes script = 3;
int64 valueZat = 4; int64 valueZat = 4;
uint64 height = 5; uint64 height = 5;
} }
message GetAddressUtxosReplyList { message GetAddressUtxosReplyList {
repeated GetAddressUtxosReply addressUtxos = 1; repeated GetAddressUtxosReply addressUtxos = 1;
} }
service CompactTxStreamer { service CompactTxStreamer {
// Return the height of the tip of the best chain // Return the height of the tip of the best chain
rpc GetLatestBlock(ChainSpec) returns (BlockID) {} rpc GetLatestBlock(ChainSpec) returns (BlockID) {}
// Return the compact block corresponding to the given block identifier // Return the compact block corresponding to the given block identifier
rpc GetBlock(BlockID) returns (CompactBlock) {} rpc GetBlock(BlockID) returns (CompactBlock) {}
// Return a list of consecutive compact blocks // Return a list of consecutive compact blocks
rpc GetBlockRange(BlockRange) returns (stream CompactBlock) {} rpc GetBlockRange(BlockRange) returns (stream CompactBlock) {}
// Return the requested full (not compact) transaction (as from zcashd) // Return the requested full (not compact) transaction (as from zcashd)
rpc GetTransaction(TxFilter) returns (RawTransaction) {} rpc GetTransaction(TxFilter) returns (RawTransaction) {}
// Submit the given transaction to the Zcash network // Submit the given transaction to the Zcash network
rpc SendTransaction(RawTransaction) returns (SendResponse) {} rpc SendTransaction(RawTransaction) returns (SendResponse) {}
// Return the txids corresponding to the given t-address within the given block range // Return the txids corresponding to the given t-address within the given block range
rpc GetTaddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {} rpc GetTaddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {}
// wrapper for GetTaddressTxids // wrapper for GetTaddressTxids
rpc GetAddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {} rpc GetAddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {}
rpc GetTaddressBalance(AddressList) returns (Balance) {} rpc GetTaddressBalance(AddressList) returns (Balance) {}
rpc GetTaddressBalanceStream(stream Address) returns (Balance) {} rpc GetTaddressBalanceStream(stream Address) returns (Balance) {}
// Return the compact transactions currently in the mempool; the results // Return the compact transactions currently in the mempool; the results
// can be a few seconds out of date. If the Exclude list is empty, return // can be a few seconds out of date. If the Exclude list is empty, return
// all transactions; otherwise return all *except* those in the Exclude list // all transactions; otherwise return all *except* those in the Exclude list
// (if any); this allows the client to avoid receiving transactions that it // (if any); this allows the client to avoid receiving transactions that it
// already has (from an earlier call to this rpc). The transaction IDs in the // already has (from an earlier call to this rpc). The transaction IDs in the
// Exclude list can be shortened to any number of bytes to make the request // Exclude list can be shortened to any number of bytes to make the request
// more bandwidth-efficient; if two or more transactions in the mempool // more bandwidth-efficient; if two or more transactions in the mempool
// match a shortened txid, they are all sent (none is excluded). Transactions // match a shortened txid, they are all sent (none is excluded). Transactions
// in the exclude list that don't exist in the mempool are ignored. // in the exclude list that don't exist in the mempool are ignored.
rpc GetMempoolTx(Exclude) returns (stream CompactTx) {} rpc GetMempoolTx(Exclude) returns (stream CompactTx) {}
// Return a stream of current Mempool transactions. This will keep the output stream open while // Return a stream of current Mempool transactions. This will keep the output stream open while
// there are mempool transactions. It will close the returned stream when a new block is mined. // there are mempool transactions. It will close the returned stream when a new block is mined.
rpc GetMempoolStream(Empty) returns (stream RawTransaction) {} rpc GetMempoolStream(Empty) returns (stream RawTransaction) {}
// GetTreeState returns the note commitment tree state corresponding to the given block. // GetTreeState returns the note commitment tree state corresponding to the given block.
// See section 3.7 of the Zcash protocol specification. It returns several other useful // See section 3.7 of the Zcash protocol specification. It returns several other useful
// values also (even though they can be obtained using GetBlock). // values also (even though they can be obtained using GetBlock).
// The block can be specified by either height or hash. // The block can be specified by either height or hash.
rpc GetTreeState(BlockID) returns (TreeState) {} rpc GetTreeState(BlockID) returns (TreeState) {}
rpc GetLatestTreeState(Empty) returns (TreeState) {} rpc GetLatestTreeState(Empty) returns (TreeState) {}
rpc GetAddressUtxos(GetAddressUtxosArg) returns (GetAddressUtxosReplyList) {} rpc GetAddressUtxos(GetAddressUtxosArg) returns (GetAddressUtxosReplyList) {}
rpc GetAddressUtxosStream(GetAddressUtxosArg) returns (stream GetAddressUtxosReply) {} rpc GetAddressUtxosStream(GetAddressUtxosArg) returns (stream GetAddressUtxosReply) {}
// Return information about this lightwalletd instance and the blockchain // Return information about this lightwalletd instance and the blockchain
rpc GetLightdInfo(Empty) returns (LightdInfo) {} rpc GetLightdInfo(Empty) returns (LightdInfo) {}
// Testing-only, requires lightwalletd --ping-very-insecure (do not enable in production) // Testing-only, requires lightwalletd --ping-very-insecure (do not enable in production)
// rpc Ping(Duration) returns (PingResponse) {} // rpc Ping(Duration) returns (PingResponse) {}
rpc GetCoinsupply(Empty) returns (Coinsupply) {} rpc GetCoinsupply(Empty) returns (Coinsupply) {}
} }
+975 -975
View File
File diff suppressed because it is too large Load Diff
+363 -366
View File
@@ -1,366 +1,363 @@
// Copyright The Hush Developers 2019-2022 // Copyright The Hush Developers 2019-2022
// Released under the GPLv3 // Released under the GPLv3
use log::{info,error}; use log::{info,error};
use std::sync::Arc; use std::sync::Arc;
use zcash_primitives::transaction::{TxId}; use zcash_primitives::transaction::{TxId};
use crate::grpc_client::{ChainSpec, BlockId, BlockRange, RawTransaction, CompactBlock, use crate::grpc_client::{ChainSpec, BlockId, BlockRange, RawTransaction, CompactBlock,
TransparentAddressBlockFilter, TxFilter, Empty, LightdInfo, Coinsupply}; TransparentAddressBlockFilter, TxFilter, Empty, LightdInfo, Coinsupply};
use tonic::transport::{Channel, ClientTlsConfig}; use tonic::transport::{Channel, ClientTlsConfig};
use tokio_rustls::{rustls::ClientConfig}; use tokio_rustls::{rustls::ClientConfig};
use tonic::{Request}; use tonic::{Request};
use threadpool::ThreadPool; use threadpool::ThreadPool;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use crate::PubCertificate; use crate::PubCertificate;
use crate::grpc_client::compact_tx_streamer_client::CompactTxStreamerClient; use crate::grpc_client::compact_tx_streamer_client::CompactTxStreamerClient;
mod danger { mod danger {
use tokio_rustls::rustls; use tokio_rustls::rustls;
use webpki; use webpki;
pub struct NoCertificateVerification {} pub struct NoCertificateVerification {}
impl rustls::ServerCertVerifier for NoCertificateVerification { impl rustls::ServerCertVerifier for NoCertificateVerification {
fn verify_server_cert(&self, fn verify_server_cert(&self,
_roots: &rustls::RootCertStore, _roots: &rustls::RootCertStore,
_presented_certs: &[rustls::Certificate], _presented_certs: &[rustls::Certificate],
_dns_name: webpki::DNSNameRef<'_>, _dns_name: webpki::DNSNameRef<'_>,
_ocsp: &[u8]) -> Result<rustls::ServerCertVerified, rustls::TLSError> { _ocsp: &[u8]) -> Result<rustls::ServerCertVerified, rustls::TLSError> {
Ok(rustls::ServerCertVerified::assertion()) Ok(rustls::ServerCertVerified::assertion())
} }
} }
} }
async fn get_client(uri: &http::Uri, no_cert: bool) -> Result<CompactTxStreamerClient<Channel>, Box<dyn std::error::Error>> { async fn get_client(uri: &http::Uri, no_cert: bool) -> Result<CompactTxStreamerClient<Channel>, Box<dyn std::error::Error>> {
let channel = if uri.scheme_str() == Some("http") { let channel = if uri.scheme_str() == Some("http") {
Channel::builder(uri.clone()).connect().await? Channel::builder(uri.clone()).connect().await?
} else { } else {
let mut config = ClientConfig::new(); let mut config = ClientConfig::new();
config.alpn_protocols.push(b"h2".to_vec()); config.alpn_protocols.push(b"h2".to_vec());
config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
config.root_store.add_pem_file( config.root_store.add_pem_file(
&mut PubCertificate::get("lightwalletd-lite.myhush.pem").unwrap().as_ref()).unwrap(); &mut PubCertificate::get("lightwalletd-lite.myhush.pem").unwrap().as_ref()).unwrap();
if no_cert { if no_cert {
config.dangerous() config.dangerous()
.set_certificate_verifier(Arc::new(danger::NoCertificateVerification {})); .set_certificate_verifier(Arc::new(danger::NoCertificateVerification {}));
} }
let tls = ClientTlsConfig::new() let tls = ClientTlsConfig::new()
.rustls_client_config(config) .rustls_client_config(config)
.domain_name(uri.host().unwrap()); .domain_name(uri.host().unwrap());
Channel::builder(uri.clone()) Channel::builder(uri.clone())
.tls_config(tls) .tls_config(tls)
.connect() .connect()
.await? .await?
}; };
Ok(CompactTxStreamerClient::new(channel)) Ok(CompactTxStreamerClient::new(channel))
} }
// ============== // ==============
// GRPC code // GRPC code
// ============== // ==============
async fn get_lightd_info(uri: &http::Uri, no_cert: bool) -> Result<LightdInfo, Box<dyn std::error::Error>> { async fn get_lightd_info(uri: &http::Uri, no_cert: bool) -> Result<LightdInfo, Box<dyn std::error::Error>> {
let mut client = get_client(uri, no_cert).await?; let mut client = get_client(uri, no_cert).await?;
let request = Request::new(Empty {}); let request = Request::new(Empty {});
let response = client.get_lightd_info(request).await?; let response = client.get_lightd_info(request).await?;
Ok(response.into_inner()) Ok(response.into_inner())
} }
pub fn get_info(uri: &http::Uri, no_cert: bool) -> Result<LightdInfo, String> { pub fn get_info(uri: &http::Uri, no_cert: bool) -> Result<LightdInfo, String> {
let mut rt = tokio::runtime::Runtime::new().map_err(|e| e.to_string())?; let mut rt = tokio::runtime::Runtime::new().map_err(|e| e.to_string())?;
rt.block_on(get_lightd_info(uri, no_cert)).map_err( |e| e.to_string()) rt.block_on(get_lightd_info(uri, no_cert)).map_err( |e| e.to_string())
} }
async fn get_coinsupply_info(uri: &http::Uri, no_cert: bool) -> Result<Coinsupply, Box<dyn std::error::Error>> { async fn get_coinsupply_info(uri: &http::Uri, no_cert: bool) -> Result<Coinsupply, Box<dyn std::error::Error>> {
let mut client = get_client(uri, no_cert).await?; let mut client = get_client(uri, no_cert).await?;
let request = Request::new(Empty {}); let request = Request::new(Empty {});
let response = client.get_coinsupply(request).await?; let response = client.get_coinsupply(request).await?;
Ok(response.into_inner()) Ok(response.into_inner())
} }
pub fn get_coinsupply(uri: http::Uri, no_cert: bool) -> Result<Coinsupply, String> { pub fn get_coinsupply(uri: http::Uri, no_cert: bool) -> Result<Coinsupply, String> {
let mut rt = tokio::runtime::Runtime::new().map_err(|e| e.to_string())?; let mut rt = tokio::runtime::Runtime::new().map_err(|e| e.to_string())?;
rt.block_on(get_coinsupply_info(&uri, no_cert)).map_err( |e| e.to_string()) rt.block_on(get_coinsupply_info(&uri, no_cert)).map_err( |e| e.to_string())
} }
async fn get_block_range<F : 'static + std::marker::Send>( async fn get_block_range<F : 'static + std::marker::Send>(
uri: &http::Uri, uri: &http::Uri,
start_height: u64, start_height: u64,
end_height: u64, end_height: u64,
no_cert: bool, no_cert: bool,
pool: ThreadPool, pool: ThreadPool,
c: F c: F
) -> Result<(), Box<dyn std::error::Error>> ) -> Result<(), Box<dyn std::error::Error>>
where F : Fn(&[u8], u64) { where F : Fn(&[u8], u64) {
let mut client = get_client(uri, no_cert).await?; let mut client = get_client(uri, no_cert).await?;
let bs = BlockId { height: start_height, hash: vec![] }; let bs = BlockId { height: start_height, hash: vec![] };
let be = BlockId { height: end_height, hash: vec![] }; let be = BlockId { height: end_height, hash: vec![] };
let request = Request::new(BlockRange { start: Some(bs), end: Some(be) }); let request = Request::new(BlockRange { start: Some(bs), end: Some(be) });
let (tx, rx) = channel::<Option<CompactBlock>>(); let (tx, rx) = channel::<Option<CompactBlock>>();
let (ftx, frx) = channel(); let (ftx, frx) = channel();
pool.execute(move || { pool.execute(move || {
while let Ok(Some(block)) = rx.recv() { while let Ok(Some(block)) = rx.recv() {
use prost::Message; use prost::Message;
let mut encoded_buf = vec![]; let mut encoded_buf = vec![];
if let Err(e) = block.encode(&mut encoded_buf) { if let Err(e) = block.encode(&mut encoded_buf) {
error!("Error encoding block: {:?}", e); error!("Error encoding block: {:?}", e);
break; break;
} }
c(&encoded_buf, block.height); c(&encoded_buf, block.height);
} }
if let Err(e) = ftx.send(Ok(())) { if let Err(e) = ftx.send(Ok(())) {
error!("Error sending completion signal: {:?}", e); error!("Error sending completion signal: {:?}", e);
} }
}); });
let mut response = client.get_block_range(request).await?.into_inner(); let mut response = client.get_block_range(request).await?.into_inner();
while let Some(block) = response.message().await? { while let Some(block) = response.message().await? {
if let Err(e) = tx.send(Some(block)) { if let Err(e) = tx.send(Some(block)) {
error!("Error sending block to channel: {:?}", e); error!("Error sending block to channel: {:?}", e);
break; break;
} }
} }
if let Err(e) = tx.send(None) { if let Err(e) = tx.send(None) {
error!("Error sending end signal to channel: {:?}", e); error!("Error sending end signal to channel: {:?}", e);
} }
frx.iter().take(1).collect::<Result<Vec<()>, String>>()?; frx.iter().take(1).collect::<Result<Vec<()>, String>>()?;
Ok(()) Ok(())
} }
pub fn fetch_blocks<F : 'static + std::marker::Send>(uri: &http::Uri, start_height: u64, end_height: u64, no_cert: bool, pool: ThreadPool, c: F) -> Result<(), String> pub fn fetch_blocks<F : 'static + std::marker::Send>(uri: &http::Uri, start_height: u64, end_height: u64, no_cert: bool, pool: ThreadPool, c: F) -> Result<(), String>
where F : Fn(&[u8], u64) { where F : Fn(&[u8], u64) {
let mut rt = tokio::runtime::Runtime::new().map_err(|e| format!("Error creating runtime {:?}", e))?;
let mut rt = match tokio::runtime::Runtime::new() { fetch_blocks_with_runtime(&mut rt, uri, start_height, end_height, no_cert, pool, c)
Ok(r) => r, }
Err(e) => {
let es = format!("Error creating runtime {:?}", e); pub fn fetch_blocks_with_runtime<F : 'static + std::marker::Send>(rt: &mut tokio::runtime::Runtime, uri: &http::Uri, start_height: u64, end_height: u64, no_cert: bool, pool: ThreadPool, c: F) -> Result<(), String>
error!("{}", es); where F : Fn(&[u8], u64) {
return Err(es);
} match rt.block_on(get_block_range(uri, start_height, end_height, no_cert, pool, c)) {
}; Ok(o) => Ok(o),
Err(e) => {
match rt.block_on(get_block_range(uri, start_height, end_height, no_cert, pool, c)) { let e = format!("Error fetching blocks {:?}", e);
Ok(o) => Ok(o), error!("{}", e);
Err(e) => { Err(e)
let e = format!("Error fetching blocks {:?}", e); }
error!("{}", e); }
Err(e) }
}
} // get_address_txids GRPC call
} async fn get_address_txids<F : 'static + std::marker::Send>(
uri: &http::Uri,
// get_address_txids GRPC call address: String,
async fn get_address_txids<F : 'static + std::marker::Send>( start_height: u64,
uri: &http::Uri, end_height: u64,
address: String, no_cert: bool,
start_height: u64, c: F
end_height: u64, ) -> Result<(), Box<dyn std::error::Error>>
no_cert: bool, where F : Fn(&[u8], u64) {
c: F
) -> Result<(), Box<dyn std::error::Error>> let mut client = match get_client(uri, no_cert).await {
where F : Fn(&[u8], u64) { Ok(client) => client,
Err(e) => {
let mut client = match get_client(uri, no_cert).await { error!("Error creating client: {:?}", e);
Ok(client) => client, return Err(e.into());
Err(e) => { }
error!("Error creating client: {:?}", e); };
return Err(e.into());
} let start = Some(BlockId{ height: start_height, hash: vec!()});
}; let end = Some(BlockId{ height: end_height, hash: vec!()});
let start = Some(BlockId{ height: start_height, hash: vec!()}); let request = Request::new(TransparentAddressBlockFilter{ address, range: Some(BlockRange{ start, end }) });
let end = Some(BlockId{ height: end_height, hash: vec!()});
let maybe_response = match client.get_address_txids(request).await {
let request = Request::new(TransparentAddressBlockFilter{ address, range: Some(BlockRange{ start, end }) }); Ok(response) => response,
Err(e) => {
let maybe_response = match client.get_address_txids(request).await { error!("Error getting address txids: {:?}", e);
Ok(response) => response, return Err(e.into());
Err(e) => { }
error!("Error getting address txids: {:?}", e); };
return Err(e.into());
} let mut response = maybe_response.into_inner();
};
while let Some(tx) = response.message().await? {
let mut response = maybe_response.into_inner(); c(&tx.data, tx.height);
}
while let Some(tx) = response.message().await? {
c(&tx.data, tx.height); Ok(())
} }
Ok(()) // function to monitor mempool transactions
} pub async fn monitor_mempool<F: 'static + std::marker::Send>(
uri: &http::Uri,
// function to monitor mempool transactions no_cert: bool,
pub async fn monitor_mempool<F: 'static + std::marker::Send>( mut c: F
uri: &http::Uri, ) -> Result<(), Box<dyn std::error::Error>>
no_cert: bool, where
mut c: F F: FnMut(RawTransaction) -> Result<(), Box<dyn std::error::Error>>,
) -> Result<(), Box<dyn std::error::Error>> {
where
F: FnMut(RawTransaction) -> Result<(), Box<dyn std::error::Error>>, let mut client = get_client(uri, no_cert)
{ .await
.map_err(|e| format!("Error getting client: {:?}", e))?;
let mut client = get_client(uri, no_cert)
.await
.map_err(|e| format!("Error getting client: {:?}", e))?; let request = Request::new(Empty {});
let mut response = client
let request = Request::new(Empty {}); .get_mempool_stream(request)
.await
let mut response = client .map_err(|e| format!("{}", e))?
.get_mempool_stream(request) .into_inner();
.await
.map_err(|e| format!("{}", e))?
.into_inner(); while let Ok(Some(rtx)) = response.message().await {
if let Err(e) = c(rtx) {
while let Ok(Some(rtx)) = response.message().await { info!("Error processing RawTransaction: {:?}", e);
}
if let Err(e) = c(rtx) { }
info!("Error processing RawTransaction: {:?}", e);
} Ok(())
} }
Ok(()) pub fn fetch_transparent_txids<F : 'static + std::marker::Send>(
} uri: &http::Uri,
address: String,
pub fn fetch_transparent_txids<F : 'static + std::marker::Send>( start_height: u64,
uri: &http::Uri, end_height: u64,
address: String, no_cert: bool,
start_height: u64, c: F
end_height: u64, ) -> Result<(), String>
no_cert: bool, where F : Fn(&[u8], u64) {
c: F
) -> Result<(), String> let mut rt = match tokio::runtime::Runtime::new() {
where F : Fn(&[u8], u64) { Ok(r) => r,
Err(e) => {
let mut rt = match tokio::runtime::Runtime::new() { let e = format!("Error creating runtime {:?}", e);
Ok(r) => r, error!("{}", e);
Err(e) => { return Err(e);
let e = format!("Error creating runtime {:?}", e); }
error!("{}", e); };
return Err(e);
} match rt.block_on(get_address_txids(uri, address.clone(), start_height, end_height, no_cert, c)) {
}; Ok(o) => Ok(o),
Err(e) => {
match rt.block_on(get_address_txids(uri, address.clone(), start_height, end_height, no_cert, c)) { let e = format!("Error with get_address_txids runtime {:?}", e);
Ok(o) => Ok(o), error!("{}", e);
Err(e) => { return Err(e)
let e = format!("Error with get_address_txids runtime {:?}", e); }
error!("{}", e); }
return Err(e) }
}
} // get_transaction GRPC call
} async fn get_transaction(uri: &http::Uri, txid: TxId, no_cert: bool)
-> Result<RawTransaction, Box<dyn std::error::Error>> {
// get_transaction GRPC call let mut client = get_client(uri, no_cert).await?;
async fn get_transaction(uri: &http::Uri, txid: TxId, no_cert: bool) let request = Request::new(TxFilter { block: None, index: 0, hash: txid.0.to_vec() });
-> Result<RawTransaction, Box<dyn std::error::Error>> {
let mut client = get_client(uri, no_cert).await?; let response = client.get_transaction(request).await?;
let request = Request::new(TxFilter { block: None, index: 0, hash: txid.0.to_vec() });
Ok(response.into_inner())
let response = client.get_transaction(request).await?; }
Ok(response.into_inner()) pub fn fetch_full_tx(uri: &http::Uri, txid: TxId, no_cert: bool) -> Result<Vec<u8>, String> {
} let mut rt = match tokio::runtime::Runtime::new() {
Ok(r) => r,
pub fn fetch_full_tx(uri: &http::Uri, txid: TxId, no_cert: bool) -> Result<Vec<u8>, String> { Err(e) => {
let mut rt = match tokio::runtime::Runtime::new() { let errstr = format!("Error creating runtime {}", e.to_string());
Ok(r) => r, error!("{}", errstr);
Err(e) => { return Err(errstr);
let errstr = format!("Error creating runtime {}", e.to_string()); }
error!("{}", errstr); };
return Err(errstr);
} match rt.block_on(get_transaction(uri, txid, no_cert)) {
}; Ok(rawtx) => Ok(rawtx.data.to_vec()),
Err(e) => {
match rt.block_on(get_transaction(uri, txid, no_cert)) { let errstr = format!("Error in get_transaction runtime {}", e.to_string());
Ok(rawtx) => Ok(rawtx.data.to_vec()), error!("{}", errstr);
Err(e) => { Err(errstr)
let errstr = format!("Error in get_transaction runtime {}", e.to_string()); }
error!("{}", errstr); }
Err(errstr) }
}
} // send_transaction GRPC call
} async fn send_transaction(uri: &http::Uri, no_cert: bool, tx_bytes: Box<[u8]>) -> Result<String, Box<dyn std::error::Error>> {
let mut client = get_client(uri, no_cert).await?;
// send_transaction GRPC call
async fn send_transaction(uri: &http::Uri, no_cert: bool, tx_bytes: Box<[u8]>) -> Result<String, Box<dyn std::error::Error>> { let request = Request::new(RawTransaction {data: tx_bytes.to_vec(), height: 0});
let mut client = get_client(uri, no_cert).await?;
let response = client.send_transaction(request).await?;
let request = Request::new(RawTransaction {data: tx_bytes.to_vec(), height: 0});
let sendresponse = response.into_inner();
let response = client.send_transaction(request).await?; if sendresponse.error_code == 0 {
let mut txid = sendresponse.error_message;
let sendresponse = response.into_inner(); if txid.starts_with("\"") && txid.ends_with("\"") {
if sendresponse.error_code == 0 { txid = txid[1..txid.len()-1].to_string();
let mut txid = sendresponse.error_message; }
if txid.starts_with("\"") && txid.ends_with("\"") {
txid = txid[1..txid.len()-1].to_string(); Ok(txid)
} } else {
Err(Box::from(format!("Error: {:?}", sendresponse)))
Ok(txid) }
} else { }
Err(Box::from(format!("Error: {:?}", sendresponse)))
} pub fn broadcast_raw_tx(uri: &http::Uri, no_cert: bool, tx_bytes: Box<[u8]>) -> Result<String, String> {
} let mut rt = tokio::runtime::Runtime::new().map_err(|e| e.to_string())?;
pub fn broadcast_raw_tx(uri: &http::Uri, no_cert: bool, tx_bytes: Box<[u8]>) -> Result<String, String> { rt.block_on(send_transaction(uri, no_cert, tx_bytes)).map_err( |e| e.to_string())
let mut rt = tokio::runtime::Runtime::new().map_err(|e| e.to_string())?; }
rt.block_on(send_transaction(uri, no_cert, tx_bytes)).map_err( |e| e.to_string()) // get_latest_block GRPC call
} async fn get_latest_block(uri: &http::Uri, no_cert: bool) -> Result<BlockId, Box<dyn std::error::Error>> {
let mut client = get_client(uri, no_cert).await?;
// get_latest_block GRPC call
async fn get_latest_block(uri: &http::Uri, no_cert: bool) -> Result<BlockId, Box<dyn std::error::Error>> { let request = Request::new(ChainSpec {});
let mut client = get_client(uri, no_cert).await?;
let response = client.get_latest_block(request).await?;
let request = Request::new(ChainSpec {});
Ok(response.into_inner())
let response = client.get_latest_block(request).await?; }
Ok(response.into_inner()) pub fn fetch_latest_block(uri: &http::Uri, no_cert: bool) -> Result<BlockId, String> {
} let mut rt = match tokio::runtime::Runtime::new() {
Ok(r) => r,
pub fn fetch_latest_block(uri: &http::Uri, no_cert: bool) -> Result<BlockId, String> { Err(e) => {
let mut rt = match tokio::runtime::Runtime::new() { let errstr = format!("Error creating runtime {}", e.to_string());
Ok(r) => r, error!("{}", errstr);
Err(e) => { return Err(errstr);
let errstr = format!("Error creating runtime {}", e.to_string()); }
error!("{}", errstr); };
return Err(errstr);
} rt.block_on(get_latest_block(uri, no_cert)).map_err(|e| {
}; let errstr = format!("Error getting latest block {}", e.to_string());
error!("{}", errstr);
rt.block_on(get_latest_block(uri, no_cert)).map_err(|e| { errstr
let errstr = format!("Error getting latest block {}", e.to_string()); })
error!("{}", errstr); }
errstr
})
}
+25 -25
View File
@@ -1,25 +1,25 @@
// Copyright The Hush Developers 2019-2022 // Copyright The Hush Developers 2019-2022
// Released under the GPLv3 // Released under the GPLv3
#[macro_use] #[macro_use]
extern crate rust_embed; extern crate rust_embed;
pub mod lightclient; pub mod lightclient;
pub mod grpcconnector; pub mod grpcconnector;
pub mod lightwallet; pub mod lightwallet;
pub mod commands; pub mod commands;
#[cfg(feature = "embed_params")] #[cfg(feature = "embed_params")]
#[derive(RustEmbed)] #[derive(RustEmbed)]
#[folder = "zcash-params/"] #[folder = "zcash-params/"]
pub struct SaplingParams; pub struct SaplingParams;
#[derive(RustEmbed)] #[derive(RustEmbed)]
#[folder = "res/"] #[folder = "res/"]
pub struct PubCertificate; pub struct PubCertificate;
pub const ANCHOR_OFFSET: u32 = 0; pub const ANCHOR_OFFSET: u32 = 0;
pub mod grpc_client { pub mod grpc_client {
tonic::include_proto!("cash.z.wallet.sdk.rpc"); tonic::include_proto!("cash.z.wallet.sdk.rpc");
} }
+1802 -1798
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2554 -2527
View File
File diff suppressed because it is too large Load Diff
+46 -46
View File
@@ -1,46 +1,46 @@
//! Structs for handling supported address types. //! Structs for handling supported address types.
use pairing::bls12_381::Bls12; use pairing::bls12_381::Bls12;
use zcash_primitives::primitives::PaymentAddress; use zcash_primitives::primitives::PaymentAddress;
use zcash_client_backend::encoding::{decode_payment_address, decode_transparent_address}; use zcash_client_backend::encoding::{decode_payment_address, decode_transparent_address};
use zcash_primitives::legacy::TransparentAddress; use zcash_primitives::legacy::TransparentAddress;
/// An address that funds can be sent to. /// An address that funds can be sent to.
pub enum RecipientAddress { pub enum RecipientAddress {
Shielded(PaymentAddress<Bls12>), Shielded(PaymentAddress<Bls12>),
Transparent(TransparentAddress), Transparent(TransparentAddress),
} }
impl From<PaymentAddress<Bls12>> for RecipientAddress { impl From<PaymentAddress<Bls12>> for RecipientAddress {
fn from(addr: PaymentAddress<Bls12>) -> Self { fn from(addr: PaymentAddress<Bls12>) -> Self {
RecipientAddress::Shielded(addr) RecipientAddress::Shielded(addr)
} }
} }
impl From<TransparentAddress> for RecipientAddress { impl From<TransparentAddress> for RecipientAddress {
fn from(addr: TransparentAddress) -> Self { fn from(addr: TransparentAddress) -> Self {
RecipientAddress::Transparent(addr) RecipientAddress::Transparent(addr)
} }
} }
impl RecipientAddress { impl RecipientAddress {
pub fn from_str(s: &str, hrp_sapling_address: &str, b58_pubkey_address: [u8; 1], b58_script_address: [u8; 1]) -> Option<Self> { pub fn from_str(s: &str, hrp_sapling_address: &str, b58_pubkey_address: [u8; 1], b58_script_address: [u8; 1]) -> Option<Self> {
// Try to match a sapling z address // Try to match a sapling z address
if let Some(pa) = match decode_payment_address(hrp_sapling_address, s) { if let Some(pa) = match decode_payment_address(hrp_sapling_address, s) {
Ok(ret) => ret, Ok(ret) => ret,
Err(_) => None Err(_) => None
} }
{ {
Some(RecipientAddress::Shielded(pa)) // Matched a shielded address Some(RecipientAddress::Shielded(pa)) // Matched a shielded address
} else if let Some(addr) = match decode_transparent_address( } else if let Some(addr) = match decode_transparent_address(
&b58_pubkey_address, &b58_script_address, s) { &b58_pubkey_address, &b58_script_address, s) {
Ok(ret) => ret, Ok(ret) => ret,
Err(_) => None Err(_) => None
} }
{ {
Some(RecipientAddress::Transparent(addr)) // Matched a transparent address Some(RecipientAddress::Transparent(addr)) // Matched a transparent address
} else { } else {
None // Didn't match anything None // Didn't match anything
} }
} }
} }
File diff suppressed because it is too large Load Diff
+126 -126
View File
@@ -1,126 +1,126 @@
use ring::{ use ring::{
hmac::{self, Context, Key}, hmac::{self, Context, Key},
}; };
use lazy_static::lazy_static; use lazy_static::lazy_static;
use secp256k1::{PublicKey, Secp256k1, SecretKey, SignOnly, VerifyOnly, Error}; use secp256k1::{PublicKey, Secp256k1, SecretKey, SignOnly, VerifyOnly, Error};
lazy_static! { lazy_static! {
static ref SECP256K1_SIGN_ONLY: Secp256k1<SignOnly> = Secp256k1::signing_only(); static ref SECP256K1_SIGN_ONLY: Secp256k1<SignOnly> = Secp256k1::signing_only();
static ref SECP256K1_VERIFY_ONLY: Secp256k1<VerifyOnly> = Secp256k1::verification_only(); static ref SECP256K1_VERIFY_ONLY: Secp256k1<VerifyOnly> = Secp256k1::verification_only();
} }
/// Random entropy, part of extended key. /// Random entropy, part of extended key.
type ChainCode = Vec<u8>; type ChainCode = Vec<u8>;
const HARDENED_KEY_START_INDEX: u32 = 2_147_483_648; // 2 ** 31 const HARDENED_KEY_START_INDEX: u32 = 2_147_483_648; // 2 ** 31
/// KeyIndex indicates the key type and index of a child key. /// KeyIndex indicates the key type and index of a child key.
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum KeyIndex { pub enum KeyIndex {
/// Normal key, index range is from 0 to 2 ** 31 - 1 /// Normal key, index range is from 0 to 2 ** 31 - 1
Normal(u32), Normal(u32),
/// Hardened key, index range is from 2 ** 31 to 2 ** 32 - 1 /// Hardened key, index range is from 2 ** 31 to 2 ** 32 - 1
Hardened(u32), Hardened(u32),
} }
impl KeyIndex { impl KeyIndex {
/// Check index range. /// Check index range.
pub fn is_valid(self) -> bool { pub fn is_valid(self) -> bool {
match self { match self {
KeyIndex::Normal(i) => i < HARDENED_KEY_START_INDEX, KeyIndex::Normal(i) => i < HARDENED_KEY_START_INDEX,
KeyIndex::Hardened(i) => i >= HARDENED_KEY_START_INDEX, KeyIndex::Hardened(i) => i >= HARDENED_KEY_START_INDEX,
} }
} }
/// Generate Hardened KeyIndex from normalize index value. /// Generate Hardened KeyIndex from normalize index value.
pub fn hardened_from_normalize_index(i: u32) -> Result<KeyIndex, Error> { pub fn hardened_from_normalize_index(i: u32) -> Result<KeyIndex, Error> {
if i < HARDENED_KEY_START_INDEX { if i < HARDENED_KEY_START_INDEX {
Ok(KeyIndex::Hardened(HARDENED_KEY_START_INDEX + i)) Ok(KeyIndex::Hardened(HARDENED_KEY_START_INDEX + i))
} else { } else {
Ok(KeyIndex::Hardened(i)) Ok(KeyIndex::Hardened(i))
} }
} }
/// Generate KeyIndex from raw index value. /// Generate KeyIndex from raw index value.
pub fn from_index(i: u32) -> Result<Self, Error> { pub fn from_index(i: u32) -> Result<Self, Error> {
if i < HARDENED_KEY_START_INDEX { if i < HARDENED_KEY_START_INDEX {
Ok(KeyIndex::Normal(i)) Ok(KeyIndex::Normal(i))
} else { } else {
Ok(KeyIndex::Hardened(i)) Ok(KeyIndex::Hardened(i))
} }
} }
} }
impl From<u32> for KeyIndex { impl From<u32> for KeyIndex {
fn from(index: u32) -> Self { fn from(index: u32) -> Self {
KeyIndex::from_index(index).expect("KeyIndex") KeyIndex::from_index(index).expect("KeyIndex")
} }
} }
/// ExtendedPrivKey is used for child key derivation. /// ExtendedPrivKey is used for child key derivation.
/// See [secp256k1 crate documentation](https://docs.rs/secp256k1) for SecretKey signatures usage. /// See [secp256k1 crate documentation](https://docs.rs/secp256k1) for SecretKey signatures usage.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtendedPrivKey { pub struct ExtendedPrivKey {
pub private_key: SecretKey, pub private_key: SecretKey,
pub chain_code: ChainCode, pub chain_code: ChainCode,
} }
impl ExtendedPrivKey { impl ExtendedPrivKey {
/// Generate an ExtendedPrivKey from seed /// Generate an ExtendedPrivKey from seed
pub fn with_seed(seed: &[u8]) -> Result<ExtendedPrivKey, Error> { pub fn with_seed(seed: &[u8]) -> Result<ExtendedPrivKey, Error> {
let signature = { let signature = {
let signing_key = Key::new(hmac::HMAC_SHA512, b"Bitcoin seed"); let signing_key = Key::new(hmac::HMAC_SHA512, b"Bitcoin seed");
let mut h = Context::with_key(&signing_key); let mut h = Context::with_key(&signing_key);
h.update(&seed); h.update(&seed);
h.sign() h.sign()
}; };
let sig_bytes = signature.as_ref(); let sig_bytes = signature.as_ref();
let (key, chain_code) = sig_bytes.split_at(sig_bytes.len() / 2); let (key, chain_code) = sig_bytes.split_at(sig_bytes.len() / 2);
let private_key = SecretKey::from_slice(key)?; let private_key = SecretKey::from_slice(key)?;
Ok(ExtendedPrivKey { Ok(ExtendedPrivKey {
private_key, private_key,
chain_code: chain_code.to_vec(), chain_code: chain_code.to_vec(),
}) })
} }
fn sign_hardended_key(&self, index: u32) -> ring::hmac::Tag { fn sign_hardended_key(&self, index: u32) -> ring::hmac::Tag {
let signing_key = Key::new(hmac::HMAC_SHA512, &self.chain_code); let signing_key = Key::new(hmac::HMAC_SHA512, &self.chain_code);
let mut h = Context::with_key(&signing_key); let mut h = Context::with_key(&signing_key);
h.update(&[0x00]); h.update(&[0x00]);
h.update(&self.private_key[..]); h.update(&self.private_key[..]);
h.update(&index.to_be_bytes()); h.update(&index.to_be_bytes());
h.sign() h.sign()
} }
fn sign_normal_key(&self, index: u32) -> ring::hmac::Tag { fn sign_normal_key(&self, index: u32) -> ring::hmac::Tag {
let signing_key = Key::new(hmac::HMAC_SHA512, &self.chain_code); let signing_key = Key::new(hmac::HMAC_SHA512, &self.chain_code);
let mut h = Context::with_key(&signing_key); let mut h = Context::with_key(&signing_key);
let public_key = PublicKey::from_secret_key(&SECP256K1_SIGN_ONLY, &self.private_key); let public_key = PublicKey::from_secret_key(&SECP256K1_SIGN_ONLY, &self.private_key);
h.update(&public_key.serialize()); h.update(&public_key.serialize());
h.update(&index.to_be_bytes()); h.update(&index.to_be_bytes());
h.sign() h.sign()
} }
/// Derive a child key from ExtendedPrivKey. /// Derive a child key from ExtendedPrivKey.
pub fn derive_private_key(&self, key_index: KeyIndex) -> Result<ExtendedPrivKey, Error> { pub fn derive_private_key(&self, key_index: KeyIndex) -> Result<ExtendedPrivKey, Error> {
if !key_index.is_valid() { if !key_index.is_valid() {
return Err(Error::InvalidTweak); return Err(Error::InvalidTweak);
} }
let signature = match key_index { let signature = match key_index {
KeyIndex::Hardened(index) => self.sign_hardended_key(index), KeyIndex::Hardened(index) => self.sign_hardended_key(index),
KeyIndex::Normal(index) => self.sign_normal_key(index), KeyIndex::Normal(index) => self.sign_normal_key(index),
}; };
let sig_bytes = signature.as_ref(); let sig_bytes = signature.as_ref();
let (key, chain_code) = sig_bytes.split_at(sig_bytes.len() / 2); let (key, chain_code) = sig_bytes.split_at(sig_bytes.len() / 2);
let mut private_key = SecretKey::from_slice(key)?; let mut private_key = SecretKey::from_slice(key)?;
private_key.add_assign(&self.private_key[..])?; private_key.add_assign(&self.private_key[..])?;
Ok(ExtendedPrivKey { Ok(ExtendedPrivKey {
private_key, private_key,
chain_code: chain_code.to_vec(), chain_code: chain_code.to_vec(),
}) })
} }
} }
+123 -123
View File
@@ -1,123 +1,123 @@
//! Abstractions over the proving system and parameters for ease of use. //! Abstractions over the proving system and parameters for ease of use.
use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey}; use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey};
use pairing::bls12_381::{Bls12, Fr}; use pairing::bls12_381::{Bls12, Fr};
use zcash_primitives::{ use zcash_primitives::{
jubjub::{edwards, fs::Fs, Unknown}, jubjub::{edwards, fs::Fs, Unknown},
primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, primitives::{Diversifier, PaymentAddress, ProofGenerationKey},
redjubjub::{PublicKey, Signature}, redjubjub::{PublicKey, Signature},
transaction::components::Amount transaction::components::Amount
}; };
use zcash_primitives::{ use zcash_primitives::{
merkle_tree::CommitmentTreeWitness, prover::TxProver, sapling::Node, merkle_tree::CommitmentTreeWitness, prover::TxProver, sapling::Node,
transaction::components::GROTH_PROOF_SIZE, JUBJUB, transaction::components::GROTH_PROOF_SIZE, JUBJUB,
}; };
use zcash_proofs::sapling::SaplingProvingContext; use zcash_proofs::sapling::SaplingProvingContext;
/// An implementation of [`TxProver`] using Sapling Spend and Output parameters provided /// An implementation of [`TxProver`] using Sapling Spend and Output parameters provided
/// in-memory. /// in-memory.
pub struct InMemTxProver { pub struct InMemTxProver {
spend_params: Parameters<Bls12>, spend_params: Parameters<Bls12>,
spend_vk: PreparedVerifyingKey<Bls12>, spend_vk: PreparedVerifyingKey<Bls12>,
output_params: Parameters<Bls12>, output_params: Parameters<Bls12>,
} }
impl InMemTxProver { impl InMemTxProver {
pub fn new(spend_params: &[u8], output_params: &[u8]) -> Self { pub fn new(spend_params: &[u8], output_params: &[u8]) -> Self {
// Deserialize params // Deserialize params
let spend_params = Parameters::<Bls12>::read(spend_params, false) let spend_params = Parameters::<Bls12>::read(spend_params, false)
.expect("couldn't deserialize Sapling spend parameters file"); .expect("couldn't deserialize Sapling spend parameters file");
let output_params = Parameters::<Bls12>::read(output_params, false) let output_params = Parameters::<Bls12>::read(output_params, false)
.expect("couldn't deserialize Sapling spend parameters file"); .expect("couldn't deserialize Sapling spend parameters file");
// Prepare verifying keys // Prepare verifying keys
let spend_vk = prepare_verifying_key(&spend_params.vk); let spend_vk = prepare_verifying_key(&spend_params.vk);
InMemTxProver { InMemTxProver {
spend_params, spend_params,
spend_vk, spend_vk,
output_params, output_params,
} }
} }
} }
impl TxProver for InMemTxProver { impl TxProver for InMemTxProver {
type SaplingProvingContext = SaplingProvingContext; type SaplingProvingContext = SaplingProvingContext;
fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext { fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext {
SaplingProvingContext::new() SaplingProvingContext::new()
} }
fn spend_proof( fn spend_proof(
&self, &self,
ctx: &mut Self::SaplingProvingContext, ctx: &mut Self::SaplingProvingContext,
proof_generation_key: ProofGenerationKey<Bls12>, proof_generation_key: ProofGenerationKey<Bls12>,
diversifier: Diversifier, diversifier: Diversifier,
rcm: Fs, rcm: Fs,
ar: Fs, ar: Fs,
value: u64, value: u64,
anchor: Fr, anchor: Fr,
witness: CommitmentTreeWitness<Node>, witness: CommitmentTreeWitness<Node>,
) -> Result< ) -> Result<
( (
[u8; GROTH_PROOF_SIZE], [u8; GROTH_PROOF_SIZE],
edwards::Point<Bls12, Unknown>, edwards::Point<Bls12, Unknown>,
PublicKey<Bls12>, PublicKey<Bls12>,
), ),
(), (),
> { > {
let (proof, cv, rk) = ctx.spend_proof( let (proof, cv, rk) = ctx.spend_proof(
proof_generation_key, proof_generation_key,
diversifier, diversifier,
rcm, rcm,
ar, ar,
value, value,
anchor, anchor,
witness, witness,
&self.spend_params, &self.spend_params,
&self.spend_vk, &self.spend_vk,
&JUBJUB, &JUBJUB,
)?; )?;
let mut zkproof = [0u8; GROTH_PROOF_SIZE]; let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof proof
.write(&mut zkproof[..]) .write(&mut zkproof[..])
.expect("should be able to serialize a proof"); .expect("should be able to serialize a proof");
Ok((zkproof, cv, rk)) Ok((zkproof, cv, rk))
} }
fn output_proof( fn output_proof(
&self, &self,
ctx: &mut Self::SaplingProvingContext, ctx: &mut Self::SaplingProvingContext,
esk: Fs, esk: Fs,
payment_address: PaymentAddress<Bls12>, payment_address: PaymentAddress<Bls12>,
rcm: Fs, rcm: Fs,
value: u64, value: u64,
) -> ([u8; GROTH_PROOF_SIZE], edwards::Point<Bls12, Unknown>) { ) -> ([u8; GROTH_PROOF_SIZE], edwards::Point<Bls12, Unknown>) {
let (proof, cv) = ctx.output_proof( let (proof, cv) = ctx.output_proof(
esk, esk,
payment_address, payment_address,
rcm, rcm,
value, value,
&self.output_params, &self.output_params,
&JUBJUB, &JUBJUB,
); );
let mut zkproof = [0u8; GROTH_PROOF_SIZE]; let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof proof
.write(&mut zkproof[..]) .write(&mut zkproof[..])
.expect("should be able to serialize a proof"); .expect("should be able to serialize a proof");
(zkproof, cv) (zkproof, cv)
} }
fn binding_sig( fn binding_sig(
&self, &self,
ctx: &mut Self::SaplingProvingContext, ctx: &mut Self::SaplingProvingContext,
value_balance: Amount, value_balance: Amount,
sighash: &[u8; 32], sighash: &[u8; 32],
) -> Result<Signature, ()> { ) -> Result<Signature, ()> {
ctx.binding_sig(value_balance, sighash, &JUBJUB) ctx.binding_sig(value_balance, sighash, &JUBJUB)
} }
} }
+2339 -2339
View File
File diff suppressed because it is too large Load Diff
+20 -20
View File
@@ -1,21 +1,21 @@
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
pub fn read_string<R: Read>(mut reader: R) -> io::Result<String> { pub fn read_string<R: Read>(mut reader: R) -> io::Result<String> {
// Strings are written as <littleendian> len + bytes // Strings are written as <littleendian> len + bytes
let str_len = reader.read_u64::<LittleEndian>()?; let str_len = reader.read_u64::<LittleEndian>()?;
let mut str_bytes = vec![0; str_len as usize]; let mut str_bytes = vec![0; str_len as usize];
reader.read_exact(&mut str_bytes)?; reader.read_exact(&mut str_bytes)?;
let str = String::from_utf8(str_bytes).map_err(|e| { let str = String::from_utf8(str_bytes).map_err(|e| {
io::Error::new(io::ErrorKind::InvalidData, e.to_string()) io::Error::new(io::ErrorKind::InvalidData, e.to_string())
})?; })?;
Ok(str) Ok(str)
} }
pub fn write_string<W: Write>(mut writer: W, s: &String) -> io::Result<()> { pub fn write_string<W: Write>(mut writer: W, s: &String) -> io::Result<()> {
// Strings are written as len + utf8 // Strings are written as len + utf8
writer.write_u64::<LittleEndian>(s.as_bytes().len() as u64)?; writer.write_u64::<LittleEndian>(s.as_bytes().len() as u64)?;
writer.write_all(s.as_bytes()) writer.write_all(s.as_bytes())
} }
File diff suppressed because it is too large Load Diff
+111 -111
View File
@@ -1,111 +1,111 @@
#!/bin/bash #!/bin/bash
# This script depends on a docker image already being built # This script depends on a docker image already being built
# To build it, # To build it,
# cd docker # cd docker
# docker build --tag rustbuild:latest . # docker build --tag rustbuild:latest .
POSITIONAL=() POSITIONAL=()
while [[ $# -gt 0 ]] while [[ $# -gt 0 ]]
do do
key="$1" key="$1"
case $key in case $key in
-v|--version) -v|--version)
APP_VERSION="$2" APP_VERSION="$2"
shift # past argument shift # past argument
shift # past value shift # past value
;; ;;
*) # unknown option *) # unknown option
POSITIONAL+=("$1") # save it in an array for later POSITIONAL+=("$1") # save it in an array for later
shift # past argument shift # past argument
;; ;;
esac esac
done done
set -- "${POSITIONAL[@]}" # restore positional parameters set -- "${POSITIONAL[@]}" # restore positional parameters
if [ -z $APP_VERSION ]; then echo "APP_VERSION is not set"; exit 1; fi if [ -z $APP_VERSION ]; then echo "APP_VERSION is not set"; exit 1; fi
# Write the version file # Write the version file
echo "pub const VERSION:&str = \"$APP_VERSION\";" > /cli/src/version.rs echo "pub const VERSION:&str = \"$APP_VERSION\";" > /cli/src/version.rs
# First, do the tests # First, do the tests
cd lib && cargo test --release cd lib && cargo test --release
retVal=$? retVal=$?
if [ $retVal -ne 0 ]; then if [ $retVal -ne 0 ]; then
echo "Error" echo "Error"
exit $retVal exit $retVal
fi fi
cd .. cd ..
# Compile for mac directly # Compile for mac directly
cargo build --release cargo build --release
#macOS #macOS
rm -rf target/macOS-silentdragonxlite-cli-v$APP_VERSION rm -rf target/macOS-silentdragonxlite-cli-v$APP_VERSION
mkdir -p target/macOS-silentdragonxlite-cli-v$APP_VERSION mkdir -p target/macOS-silentdragonxlite-cli-v$APP_VERSION
cp target/release/silentdragonxlite-cli target/macOS-silentdragonxlite-cli-v$APP_VERSION/ cp target/release/silentdragonxlite-cli target/macOS-silentdragonxlite-cli-v$APP_VERSION/
# For Windows and Linux, build via docker # For Windows and Linux, build via docker
docker run --rm -v $(pwd)/:/opt/silentdragonxlite-cli rustbuild:latest bash -c "cd /opt/silentdragonxlite-cli && cargo build --release && cargo build --release --target armv7-unknown-linux-gnueabihf && cargo build --release --target aarch64-unknown-linux-gnu && SODIUM_LIB_DIR='/opt/libsodium-win64/lib/' cargo build --release --target x86_64-pc-windows-gnu" docker run --rm -v $(pwd)/:/opt/silentdragonxlite-cli rustbuild:latest bash -c "cd /opt/silentdragonxlite-cli && cargo build --release && cargo build --release --target armv7-unknown-linux-gnueabihf && cargo build --release --target aarch64-unknown-linux-gnu && SODIUM_LIB_DIR='/opt/libsodium-win64/lib/' cargo build --release --target x86_64-pc-windows-gnu"
# Now sign and zip the binaries # Now sign and zip the binaries
# macOS # macOS
gpg --batch --output target/macOS-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.sig --detach-sig target/macOS-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli gpg --batch --output target/macOS-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.sig --detach-sig target/macOS-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli
cd target cd target
cd macOS-silentdragonxlite-cli-v$APP_VERSION cd macOS-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt gsha256sum silentdragonxlite-cli > sha256sum.txt
cd .. cd ..
zip -r macOS-silentdragonxlite-cli-v$APP_VERSION.zip macOS-silentdragonxlite-cli-v$APP_VERSION zip -r macOS-silentdragonxlite-cli-v$APP_VERSION.zip macOS-silentdragonxlite-cli-v$APP_VERSION
cd .. cd ..
#Linux #Linux
rm -rf target/linux-silentdragonxlite-cli-v$APP_VERSION rm -rf target/linux-silentdragonxlite-cli-v$APP_VERSION
mkdir -p target/linux-silentdragonxlite-cli-v$APP_VERSION mkdir -p target/linux-silentdragonxlite-cli-v$APP_VERSION
cp target/release/silentdragonxlite-cli target/linux-silentdragonxlite-cli-v$APP_VERSION/ cp target/release/silentdragonxlite-cli target/linux-silentdragonxlite-cli-v$APP_VERSION/
gpg --batch --output target/linux-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.sig --detach-sig target/linux-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli gpg --batch --output target/linux-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.sig --detach-sig target/linux-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli
cd target cd target
cd linux-silentdragonxlite-cli-v$APP_VERSION cd linux-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt gsha256sum silentdragonxlite-cli > sha256sum.txt
cd .. cd ..
zip -r linux-silentdragonxlite-cli-v$APP_VERSION.zip linux-silentdragonxlite-cli-v$APP_VERSION zip -r linux-silentdragonxlite-cli-v$APP_VERSION.zip linux-silentdragonxlite-cli-v$APP_VERSION
cd .. cd ..
#Windows #Windows
rm -rf target/Windows-silentdragonxlite-cli-v$APP_VERSION rm -rf target/Windows-silentdragonxlite-cli-v$APP_VERSION
mkdir -p target/Windows-silentdragonxlite-cli-v$APP_VERSION mkdir -p target/Windows-silentdragonxlite-cli-v$APP_VERSION
cp target/x86_64-pc-windows-gnu/release/silentdragonxlite-cli.exe target/Windows-silentdragonxlite-cli-v$APP_VERSION/ cp target/x86_64-pc-windows-gnu/release/silentdragonxlite-cli.exe target/Windows-silentdragonxlite-cli-v$APP_VERSION/
gpg --batch --output target/Windows-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.sig --detach-sig target/Windows-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.exe gpg --batch --output target/Windows-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.sig --detach-sig target/Windows-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.exe
cd target cd target
cd Windows-silentdragonxlite-cli-v$APP_VERSION cd Windows-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli.exe > sha256sum.txt gsha256sum silentdragonxlite-cli.exe > sha256sum.txt
cd .. cd ..
zip -r Windows-silentdragonxlite-cli-v$APP_VERSION.zip Windows-silentdragonxlite-cli-v$APP_VERSION zip -r Windows-silentdragonxlite-cli-v$APP_VERSION.zip Windows-silentdragonxlite-cli-v$APP_VERSION
cd .. cd ..
#Armv7 #Armv7
rm -rf target/Armv7-silentdragonxlite-cli-v$APP_VERSION rm -rf target/Armv7-silentdragonxlite-cli-v$APP_VERSION
mkdir -p target/Armv7-silentdragonxlite-cli-v$APP_VERSION mkdir -p target/Armv7-silentdragonxlite-cli-v$APP_VERSION
cp target/armv7-unknown-linux-gnueabihf/release/silentdragonxlite-cli target/Armv7-silentdragonxlite-cli-v$APP_VERSION/ cp target/armv7-unknown-linux-gnueabihf/release/silentdragonxlite-cli target/Armv7-silentdragonxlite-cli-v$APP_VERSION/
gpg --batch --output target/Armv7-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.sig --detach-sig target/Armv7-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli gpg --batch --output target/Armv7-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.sig --detach-sig target/Armv7-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli
cd target cd target
cd Armv7-silentdragonxlite-cli-v$APP_VERSION cd Armv7-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt gsha256sum silentdragonxlite-cli > sha256sum.txt
cd .. cd ..
zip -r Armv7-silentdragonxlite-cli-v$APP_VERSION.zip Armv7-silentdragonxlite-cli-v$APP_VERSION zip -r Armv7-silentdragonxlite-cli-v$APP_VERSION.zip Armv7-silentdragonxlite-cli-v$APP_VERSION
cd .. cd ..
#AARCH64 #AARCH64
rm -rf target/aarch64-silentdragonxlite-cli-v$APP_VERSION rm -rf target/aarch64-silentdragonxlite-cli-v$APP_VERSION
mkdir -p target/aarch64-silentdragonxlite-cli-v$APP_VERSION mkdir -p target/aarch64-silentdragonxlite-cli-v$APP_VERSION
cp target/aarch64-unknown-linux-gnu/release/silentdragonxlite-cli target/aarch64-silentdragonxlite-cli-v$APP_VERSION/ cp target/aarch64-unknown-linux-gnu/release/silentdragonxlite-cli target/aarch64-silentdragonxlite-cli-v$APP_VERSION/
gpg --batch --output target/aarch64-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.sig --detach-sig target/aarch64-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli gpg --batch --output target/aarch64-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli.sig --detach-sig target/aarch64-silentdragonxlite-cli-v$APP_VERSION/silentdragonxlite-cli
cd target cd target
cd aarch64-silentdragonxlite-cli-v$APP_VERSION cd aarch64-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt gsha256sum silentdragonxlite-cli > sha256sum.txt
cd .. cd ..
zip -r aarch64-silentdragonxlite-cli-v$APP_VERSION.zip aarch64-silentdragonxlite-cli-v$APP_VERSION zip -r aarch64-silentdragonxlite-cli-v$APP_VERSION.zip aarch64-silentdragonxlite-cli-v$APP_VERSION
cd .. cd ..
+50 -50
View File
@@ -1,50 +1,50 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Copyright 2021-2022 The Hush Developers # Copyright 2021-2022 The Hush Developers
# Distributed under the GPLv3 software license, see the accompanying # Distributed under the GPLv3 software license, see the accompanying
# file LICENSE or https://www.gnu.org/licenses/gpl-3.0.en.html # file LICENSE or https://www.gnu.org/licenses/gpl-3.0.en.html
# Purpose: Script to build Hush silentdragonxlite on x86 64-bit arch # Purpose: Script to build Hush silentdragonxlite on x86 64-bit arch
## Usage: ./util/build.sh ## Usage: ./util/build.sh
# Check if rustc is installed on system and exits if it is not # Check if rustc is installed on system and exits if it is not
if ! [ -x "$(command -v rustc)" ]; then if ! [ -x "$(command -v rustc)" ]; then
echo 'Error: rustc is not installed. Install it and try again.' >&2 echo 'Error: rustc is not installed. Install it and try again.' >&2
exit 1 exit 1
fi fi
# Check if cargo is installed on system and exits if it is not # Check if cargo is installed on system and exits if it is not
if ! [ -x "$(command -v cargo)" ]; then if ! [ -x "$(command -v cargo)" ]; then
echo 'Error: cargo is not installed. Install it and try again.' >&2 echo 'Error: cargo is not installed. Install it and try again.' >&2
exit 1 exit 1
fi fi
# Check if rustfmt is installed on system and exits if it is not # Check if rustfmt is installed on system and exits if it is not
if ! [ -x "$(command -v rustfmt)" ]; then if ! [ -x "$(command -v rustfmt)" ]; then
echo 'Error: rustfmt is not installed. Install it and try again.' >&2 echo 'Error: rustfmt is not installed. Install it and try again.' >&2
exit 1 exit 1
fi fi
echo "" echo ""
echo "Welcome to the Hush magic folks..." echo "Welcome to the Hush magic folks..."
echo "" echo ""
echo " #### ##### # #### # # ##### # # # # ##### ##### # # # ###### " echo " #### ##### # #### # # ##### # # # # ##### ##### # # # ###### "
echo "# # # # # # # # # # # # # # # # # # ## ## # " echo "# # # # # # # # # # # # # # # # # # ## ## # "
echo " #### # # # ##### # # # ##### # # # # # # # # # ## # ##### " echo " #### # # # ##### # # # ##### # # # # # # # # # ## # ##### "
echo " # # # # # # # # # # # # # # # # # # # # " echo " # # # # # # # # # # # # # # # # # # # # "
echo "# # # # # # # # # # # # # # # # # # # # # # " echo "# # # # # # # # # # # # # # # # # # # # # # "
echo " #### ##### ###### #### ###### # ##### #### # ###### ##### # # # # ###### " echo " #### ##### ###### #### ###### # ##### #### # ###### ##### # # # # ###### "
# now to compiling... # now to compiling...
echo "" echo ""
echo "You have the requirements installed, so let's build!" echo "You have the requirements installed, so let's build!"
cargo build --release cargo build --release
# check if compile was success # check if compile was success
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "" echo ""
echo 'Error: Something went wrong and it did not build successfully... Please reach out if you need support.' >&2 echo 'Error: Something went wrong and it did not build successfully... Please reach out if you need support.' >&2
exit 1 exit 1
fi fi
echo "" echo ""
echo "Hush silentdragonxlite-cli is now compiled for you. Enjoy and reach out if you need support." echo "Hush silentdragonxlite-cli is now compiled for you. Enjoy and reach out if you need support."
echo "For options, run ./silentdragonxlite --help" echo "For options, run ./silentdragonxlite --help"