Crash fixes, reorg handling, and sync performance improvements
Some checks failed
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

View File

@@ -1,88 +1,88 @@
name: Rust
on: [push, pull_request]
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-16.04, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.38.0
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --all
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release --all
- name: Upload ubuntu/macos
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with:
name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli
- name: Upload windows
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows')
with:
name: ${{ matrix.os }}-silentdragonlite-cli.exe
path: target/release/silentdragonlite-cli.exe
linux_arm7:
name: Linux ARMv7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: armv7-unknown-linux-gnueabihf
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_armv7-silentdragonlite-cli
path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli
linux_aarch64:
name: Linux ARM64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-gnu
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target aarch64-unknown-linux-gnu
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_aarch64-silentdragonlite-cli
path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli
name: Rust
on: [push, pull_request]
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-16.04, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.38.0
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --all
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release --all
- name: Upload ubuntu/macos
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with:
name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli
- name: Upload windows
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows')
with:
name: ${{ matrix.os }}-silentdragonlite-cli.exe
path: target/release/silentdragonlite-cli.exe
linux_arm7:
name: Linux ARMv7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: armv7-unknown-linux-gnueabihf
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_armv7-silentdragonlite-cli
path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli
linux_aarch64:
name: Linux ARM64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-gnu
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target aarch64-unknown-linux-gnu
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_aarch64-silentdragonlite-cli
path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli

View File

@@ -1,104 +1,104 @@
name: Rust
on: [push, pull_request]
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.38.0
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --all
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release --all
- name: Upload ubuntu/macos
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with:
<<<<<<< HEAD
<<<<<<< HEAD
name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli
=======
name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli
=======
name: ${{ matrix.os }}-zecwallet-cli
path: target/release/zecwallet-cli
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
- name: Upload windows
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows')
with:
<<<<<<< HEAD
name: ${{ matrix.os }}-silentdragonlite-cli.exe
path: target/release/silentdragonlite-cli.exe
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
=======
name: ${{ matrix.os }}-zecwallet-cli.exe
path: target/release/zecwallet-cli.exe
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
linux_arm7:
name: Linux ARMv7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: armv7-unknown-linux-gnueabihf
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_armv7-silentdragonlite-cli
path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli
linux_aarch64:
name: Linux ARM64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-gnu
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target aarch64-unknown-linux-gnu
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_aarch64-silentdragonlite-cli
path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli
name: Rust
on: [push, pull_request]
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.38.0
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --all
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release --all
- name: Upload ubuntu/macos
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with:
<<<<<<< HEAD
<<<<<<< HEAD
name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli
=======
name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli
=======
name: ${{ matrix.os }}-zecwallet-cli
path: target/release/zecwallet-cli
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
- name: Upload windows
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows')
with:
<<<<<<< HEAD
name: ${{ matrix.os }}-silentdragonlite-cli.exe
path: target/release/silentdragonlite-cli.exe
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
=======
name: ${{ matrix.os }}-zecwallet-cli.exe
path: target/release/zecwallet-cli.exe
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
linux_arm7:
name: Linux ARMv7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: armv7-unknown-linux-gnueabihf
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_armv7-silentdragonlite-cli
path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli
linux_aarch64:
name: Linux ARM64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-gnu
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target aarch64-unknown-linux-gnu
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_aarch64-silentdragonlite-cli
path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli

View File

@@ -1,80 +1,80 @@
name: Rust
on: [push, pull_request]
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.38.0
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --all
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release --all
- name: Upload
uses: actions/upload-artifact@v1
with:
name: ${{ matrix.os }}-zecwallet-cli
path: target/release/zecwallet-cli
linux_arm7:
name: Linux ARMv7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: armv7-unknown-linux-gnueabihf
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_armv7-zecwallet-cli
path: target/armv7-unknown-linux-gnueabihf/release/zecwallet-cli
linux_aarch64:
name: Linux ARM64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-gnu
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target aarch64-unknown-linux-gnu
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_aarch64-zecwallet-cli
path: target/aarch64-unknown-linux-gnu/release/zecwallet-cli
name: Rust
on: [push, pull_request]
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.38.0
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --all
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release --all
- name: Upload
uses: actions/upload-artifact@v1
with:
name: ${{ matrix.os }}-zecwallet-cli
path: target/release/zecwallet-cli
linux_arm7:
name: Linux ARMv7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: armv7-unknown-linux-gnueabihf
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_armv7-zecwallet-cli
path: target/armv7-unknown-linux-gnueabihf/release/zecwallet-cli
linux_aarch64:
name: Linux ARM64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-gnu
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target aarch64-unknown-linux-gnu
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_aarch64-zecwallet-cli
path: target/aarch64-unknown-linux-gnu/release/zecwallet-cli

View File

@@ -1,93 +1,93 @@
name: Rust
on: [push, pull_request]
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.38.0
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --all
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release --all
- name: Upload ubuntu/macos
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with:
<<<<<<< HEAD
name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli
=======
name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli
- name: Upload windows
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows')
with:
name: ${{ matrix.os }}-silentdragonlite-cli.exe
path: target/release/silentdragonlite-cli.exe
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
linux_arm7:
name: Linux ARMv7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: armv7-unknown-linux-gnueabihf
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_armv7-silentdragonlite-cli
path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli
linux_aarch64:
name: Linux ARM64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-gnu
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target aarch64-unknown-linux-gnu
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_aarch64-silentdragonlite-cli
path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli
name: Rust
on: [push, pull_request]
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.38.0
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --all
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release --all
- name: Upload ubuntu/macos
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with:
<<<<<<< HEAD
name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli
=======
name: ${{ matrix.os }}-silentdragonlite-cli
path: target/release/silentdragonlite-cli
- name: Upload windows
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows')
with:
name: ${{ matrix.os }}-silentdragonlite-cli.exe
path: target/release/silentdragonlite-cli.exe
>>>>>>> 959755d705b18d13a8dbdf0502c47818fe7a4e94
linux_arm7:
name: Linux ARMv7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: armv7-unknown-linux-gnueabihf
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_armv7-silentdragonlite-cli
path: target/armv7-unknown-linux-gnueabihf/release/silentdragonlite-cli
linux_aarch64:
name: Linux ARM64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-gnu
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target aarch64-unknown-linux-gnu
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_aarch64-silentdragonlite-cli
path: target/aarch64-unknown-linux-gnu/release/silentdragonlite-cli

View File

@@ -1,88 +1,88 @@
name: Rust
on: [push, pull_request]
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.38.0
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --all
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release --all
- name: Upload ubuntu/macos
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with:
name: ${{ matrix.os }}-zecwallet-cli
path: target/release/zecwallet-cli
- name: Upload windows
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows')
with:
name: ${{ matrix.os }}-zecwallet-cli.exe
path: target/release/zecwallet-cli.exe
linux_arm7:
name: Linux ARMv7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: armv7-unknown-linux-gnueabihf
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_armv7-zecwallet-cli
path: target/armv7-unknown-linux-gnueabihf/release/zecwallet-cli
linux_aarch64:
name: Linux ARM64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-gnu
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target aarch64-unknown-linux-gnu
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_aarch64-zecwallet-cli
path: target/aarch64-unknown-linux-gnu/release/zecwallet-cli
name: Rust
on: [push, pull_request]
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.38.0
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
with:
command: fetch
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --all
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release --all
- name: Upload ubuntu/macos
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'macos') || contains(matrix.os, 'ubuntu')
with:
name: ${{ matrix.os }}-zecwallet-cli
path: target/release/zecwallet-cli
- name: Upload windows
uses: actions/upload-artifact@v1
if: contains(matrix.os, 'windows')
with:
name: ${{ matrix.os }}-zecwallet-cli.exe
path: target/release/zecwallet-cli.exe
linux_arm7:
name: Linux ARMv7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: armv7-unknown-linux-gnueabihf
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target armv7-unknown-linux-gnueabihf
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_armv7-zecwallet-cli
path: target/armv7-unknown-linux-gnueabihf/release/zecwallet-cli
linux_aarch64:
name: Linux ARM64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-gnu
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target aarch64-unknown-linux-gnu
- name: Upload
uses: actions/upload-artifact@v1
with:
name: linux_aarch64-zecwallet-cli
path: target/aarch64-unknown-linux-gnu/release/zecwallet-cli

14
.gitignore vendored
View File

@@ -1,7 +1,7 @@
target/
.vscode/
history.txt
/.idea/
tarpaulin-report.html
/log*
silentdragonlite-cli
target/
.vscode/
history.txt
/.idea/
tarpaulin-report.html
/log*
silentdragonlite-cli

5766
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
[workspace]
members = [
"lib",
"cli",
]
[profile.release]
[workspace]
members = [
"lib",
"cli",
]
[profile.release]
debug = false

View File

@@ -1,23 +1,23 @@
.PHONY: format help
# Help system from https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
.DEFAULT_GOAL := help
# Copyright (c) 2019-2024 Jahway603 & The Hush Developers
# Released under the GPLv3
#
# DragonX Silentdragonlite-cli Makefile
PROJECT_NAME := "silentdragonxlite-cli"
help:
@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
printf "DragonX Silentdragonlite-cli Makefile by jahway603\n"
build: ## Build the release
./util/build.sh
cp `pwd`/target/release/$(PROJECT_NAME) .
printf "DragonX silentdragonxlite-cli is ready for you\n"
clean: ## Clean the repo
cargo clean
rm $(PROJECT_NAME)
.PHONY: format help
# Help system from https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
.DEFAULT_GOAL := help
# Copyright (c) 2019-2024 Jahway603 & The Hush Developers
# Released under the GPLv3
#
# DragonX Silentdragonlite-cli Makefile
PROJECT_NAME := "silentdragonxlite-cli"
help:
@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
printf "DragonX Silentdragonlite-cli Makefile by jahway603\n"
build: ## Build the release
./util/build.sh
cp `pwd`/target/release/$(PROJECT_NAME) .
printf "DragonX silentdragonxlite-cli is ready for you\n"
clean: ## Clean the repo
cargo clean
rm $(PROJECT_NAME)

200
README.md
View File

@@ -1,100 +1,100 @@
# 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.
This will launch the interactive prompt. Type `help` to get a list of commands
## 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.
Run `silentdragonxlite-cli help` to see a list of all commands.
## Privacy
* 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...
* Also remember that t-addresses don't provide any privacy protection.
## 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.
* The log file is in `~/.silentdragonxlite/silentdragonxlite-cli.debug.log`. Wallet is stored in `~/.silentdragonxlite/silentdragonxlite-cli.dat`
### 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:
* 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
* Can select funds from multiple shielded addresses in the same transaction
* 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)
## Compiling from source
#### 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.
| Linux Version | Rust Version Tested | Command to 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 |
| Debian 11 | 1.50.0 | [USE RUSTUP](https://www.rust-lang.org/tools/install) |
| 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.
* 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
To securely install rustup by compiling it yourself:
```
git clone https://github.com/rust-lang/rustup
cd rustup
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 compilation
Run the following commands to compile on your computer.
```shell script
git clone https://git.hush.is/dragonx/silentdragonxlite-cli
cd silentdragonxlite-cli
cargo build --release
./target/release/silentdragonxlite-cli
```
#### Or build with make
Alternatively, you can use the new makefile to build
```shell script
make help
make build
```
## Options
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.
* Example: `./silentdragonxlite-cli --server 127.0.0.1:9067`
* 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
* Example: `./silentdragonxlite-cli --seed "twenty four words seed phrase"`
* `--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
### 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).
## Copyright
Copyright The Hush Developers 2019-2024
## License
GPLv3 or later
# 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.
This will launch the interactive prompt. Type `help` to get a list of commands
## 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.
Run `silentdragonxlite-cli help` to see a list of all commands.
## Privacy
* 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...
* Also remember that t-addresses don't provide any privacy protection.
## 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.
* The log file is in `~/.silentdragonxlite/silentdragonxlite-cli.debug.log`. Wallet is stored in `~/.silentdragonxlite/silentdragonxlite-cli.dat`
### 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:
* 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
* Can select funds from multiple shielded addresses in the same transaction
* 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)
## Compiling from source
#### 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.
| Linux Version | Rust Version Tested | Command to 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 |
| Debian 11 | 1.50.0 | [USE RUSTUP](https://www.rust-lang.org/tools/install) |
| 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.
* 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
To securely install rustup by compiling it yourself:
```
git clone https://github.com/rust-lang/rustup
cd rustup
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 compilation
Run the following commands to compile on your computer.
```shell script
git clone https://git.hush.is/dragonx/silentdragonxlite-cli
cd silentdragonxlite-cli
cargo build --release
./target/release/silentdragonxlite-cli
```
#### Or build with make
Alternatively, you can use the new makefile to build
```shell script
make help
make build
```
## Options
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.
* Example: `./silentdragonxlite-cli --server 127.0.0.1:9067`
* 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
* Example: `./silentdragonxlite-cli --seed "twenty four words seed phrase"`
* `--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
### 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).
## Copyright
Copyright The Hush Developers 2019-2024
## License
GPLv3 or later

View File

@@ -1,18 +1,18 @@
[package]
name = "silentdragonxlite-cli"
version = "1.0.0"
edition = "2018"
[dependencies]
rustyline = "5.0.2"
clap = "2.33"
log = "0.4"
log4rs = "0.8.3"
shellwords = "1.0.0"
json = "0.12.0"
http = "0.2"
byteorder = "1"
tiny-bip39 = "0.6.2"
silentdragonxlitelib = { path = "../lib/" }
[package]
name = "silentdragonxlite-cli"
version = "1.0.0"
edition = "2018"
[dependencies]
rustyline = "5.0.2"
clap = "2.33"
log = "0.4"
log4rs = "0.8.3"
shellwords = "1.0.0"
json = "0.12.0"
http = "0.2"
byteorder = "1"
tiny-bip39 = "0.6.2"
silentdragonxlitelib = { path = "../lib/" }

View File

@@ -1,262 +1,262 @@
use std::io::{self};
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use log::{info, error};
use silentdragonxlitelib::{commands,
lightclient::{LightClient, LightClientConfig},
};
#[macro_export]
macro_rules! configure_clapapp {
( $freshapp: expr ) => {
$freshapp.version("1.0.0")
.arg(Arg::with_name("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.")
.takes_value(false))
.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.")
.long("nosync")
.short("n")
.takes_value(false))
.arg(Arg::with_name("recover")
.long("recover")
.help("Attempt to recover the seed from the wallet")
.takes_value(false))
.arg(Arg::with_name("password")
.long("password")
.help("When recovering seed, specify a password for the encrypted wallet")
.takes_value(true))
.arg(Arg::with_name("seed")
.short("s")
.long("seed")
.value_name("seed_phrase")
.help("Create a new wallet with the given 24-word seed phrase. Will fail if wallet already exists")
.takes_value(true))
.arg(Arg::with_name("birthday")
.long("birthday")
.value_name("birthday")
.help("Specify wallet birthday when restoring from seed. This is the earlist block height where the wallet has a transaction.")
.takes_value(true))
.arg(Arg::with_name("server")
.long("server")
.value_name("server")
.help("Lightwalletd server to connect to.")
.takes_value(true)
.default_value(lightclient::DEFAULT_SERVER))
.arg(Arg::with_name("COMMAND")
.help("Command to execute. If a command is not specified, Silentdragonlite-cli will start in interactive mode.")
.required(false)
.index(1))
.arg(Arg::with_name("PARAMS")
.help("Params to execute command with. Run the 'help' command to get usage help.")
.required(false)
.multiple(true))
};
}
/// This function is only tested against Linux.
pub fn report_permission_error() {
let user = std::env::var("USER").expect(
"Unexpected error reading value of $USER!");
let home = std::env::var("HOME").expect(
"Unexpected error reading value of $HOME!");
let current_executable = std::env::current_exe()
.expect("Unexpected error reporting executable path!");
eprintln!("USER: {}", user);
eprintln!("HOME: {}", home);
eprintln!("Executable: {}", current_executable.display());
if home == "/" {
eprintln!("User {} must have permission to write to '{}.silentdragonxlite/' .",
user,
home);
} else {
eprintln!("User {} must have permission to write to '{}/.silentdragonxlite/' .",
user,
home);
}
}
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>)> {
// Try to get the configuration
let (config, latest_block_height) = LightClientConfig::create(server.clone(), dangerous)?;
let lightclient = match seed {
Some(phrase) => Arc::new(LightClient::new_from_phrase(phrase, &config, birthday,0, false)?),
None => {
if config.wallet_exists() {
Arc::new(LightClient::read_from_disk(&config)?)
} else {
println!("Creating a new wallet");
Arc::new(LightClient::new(&config, latest_block_height)?)
}
}
};
// Initialize logging
lightclient.init_logging()?;
// Print startup Messages
info!(""); // Blank line
info!("Starting Silentdragonlite-CLI");
info!("Light Client config {:?}", config);
if print_updates {
println!("Lightclient connecting to {}", config.server);
}
// At startup, run a sync.
if first_sync {
let update = lightclient.do_sync(true);
if print_updates {
match update {
Ok(j) => {
println!("{}", j.pretty(2));
},
Err(e) => println!("{}", e)
}
}
}
// Start the command loop
let (command_tx, resp_rx) = command_loop(lightclient.clone());
Ok((command_tx, resp_rx))
}
pub fn start_interactive(command_tx: Sender<(String, Vec<String>)>, resp_rx: Receiver<String>) {
// `()` can be used when no completer is required
let mut rl = rustyline::Editor::<()>::new();
println!("Ready!");
let send_command = |cmd: String, args: Vec<String>| -> String {
command_tx.send((cmd.clone(), args)).unwrap();
match resp_rx.recv() {
Ok(s) => s,
Err(e) => {
let e = format!("Error executing command {}: {}", cmd, e);
eprintln!("{}", e);
error!("{}", e);
return "".to_string()
}
}
};
let info = send_command("info".to_string(), vec![]);
let chain_name = json::parse(&info).unwrap()["chain_name"].as_str().unwrap().to_string();
loop {
// Read the height first
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') >> ",
chain_name, height));
match readline {
Ok(line) => {
rl.add_history_entry(line.as_str());
// Parse command line arguments
let mut cmd_args = match shellwords::split(&line) {
Ok(args) => args,
Err(_) => {
println!("Mismatched Quotes");
continue;
}
};
if cmd_args.is_empty() {
continue;
}
let cmd = cmd_args.remove(0);
let args: Vec<String> = cmd_args;
println!("{}", send_command(cmd, args));
// Special check for Quit command.
if line == "quit" {
break;
}
},
Err(rustyline::error::ReadlineError::Interrupted) => {
println!("CTRL-C");
info!("CTRL-C");
println!("{}", send_command("save".to_string(), vec![]));
break
},
Err(rustyline::error::ReadlineError::Eof) => {
println!("CTRL-D");
info!("CTRL-D");
println!("{}", send_command("save".to_string(), vec![]));
break
},
Err(err) => {
println!("Error: {:?}", err);
break
}
}
}
}
pub fn command_loop(lightclient: Arc<LightClient>) -> (Sender<(String, Vec<String>)>, Receiver<String>) {
let (command_tx, command_rx) = channel::<(String, Vec<String>)>();
let (resp_tx, resp_rx) = channel::<String>();
let lc = lightclient.clone();
std::thread::spawn(move || {
//start mempool_monitor
match LightClient::start_mempool_monitor(lc.clone()) {
Ok(_) => {},
Err(e) => {
error!("Error starting mempool: {:?}", e);
}
}
loop {
match command_rx.recv_timeout(std::time::Duration::from_secs(5 * 60)) {
Ok((cmd, args)) => {
let args = args.iter().map(|s| s.as_ref()).collect();
let cmd_response = commands::do_user_command(&cmd, &args, lc.as_ref());
resp_tx.send(cmd_response).unwrap();
if cmd == "quit" {
info!("Quit");
break;
}
},
Err(_) => {
// 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");
match lc.do_sync(false) {
Ok(_) => {},
Err(e) => {error!("{}", e)}
}
}
}
}
});
(command_tx, resp_rx)
}
pub fn attempt_recover_seed(password: Option<String>) {
// Create a Light Client Config in an attempt to recover the file.
let config = LightClientConfig {
server: "0.0.0.0:0".parse().unwrap(),
chain_name: "main".to_string(),
sapling_activation_height: 0,
consensus_branch_id: "000000".to_string(),
anchor_offset: 0,
no_cert_verification: false,
data_dir: None,
};
match LightClient::attempt_recover_seed(&config, password) {
Ok(_seed) => println!("Recovered seed "),
Err(e) => eprintln!("Failed to recover seed. Error: {}", e)
};
}
use std::io::{self};
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use log::{info, error};
use silentdragonxlitelib::{commands,
lightclient::{LightClient, LightClientConfig},
};
#[macro_export]
macro_rules! configure_clapapp {
( $freshapp: expr ) => {
$freshapp.version("1.0.0")
.arg(Arg::with_name("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.")
.takes_value(false))
.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.")
.long("nosync")
.short("n")
.takes_value(false))
.arg(Arg::with_name("recover")
.long("recover")
.help("Attempt to recover the seed from the wallet")
.takes_value(false))
.arg(Arg::with_name("password")
.long("password")
.help("When recovering seed, specify a password for the encrypted wallet")
.takes_value(true))
.arg(Arg::with_name("seed")
.short("s")
.long("seed")
.value_name("seed_phrase")
.help("Create a new wallet with the given 24-word seed phrase. Will fail if wallet already exists")
.takes_value(true))
.arg(Arg::with_name("birthday")
.long("birthday")
.value_name("birthday")
.help("Specify wallet birthday when restoring from seed. This is the earlist block height where the wallet has a transaction.")
.takes_value(true))
.arg(Arg::with_name("server")
.long("server")
.value_name("server")
.help("Lightwalletd server to connect to.")
.takes_value(true)
.default_value(lightclient::DEFAULT_SERVER))
.arg(Arg::with_name("COMMAND")
.help("Command to execute. If a command is not specified, Silentdragonlite-cli will start in interactive mode.")
.required(false)
.index(1))
.arg(Arg::with_name("PARAMS")
.help("Params to execute command with. Run the 'help' command to get usage help.")
.required(false)
.multiple(true))
};
}
/// This function is only tested against Linux.
pub fn report_permission_error() {
let user = std::env::var("USER").expect(
"Unexpected error reading value of $USER!");
let home = std::env::var("HOME").expect(
"Unexpected error reading value of $HOME!");
let current_executable = std::env::current_exe()
.expect("Unexpected error reporting executable path!");
eprintln!("USER: {}", user);
eprintln!("HOME: {}", home);
eprintln!("Executable: {}", current_executable.display());
if home == "/" {
eprintln!("User {} must have permission to write to '{}.silentdragonxlite/' .",
user,
home);
} else {
eprintln!("User {} must have permission to write to '{}/.silentdragonxlite/' .",
user,
home);
}
}
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>)> {
// Try to get the configuration
let (config, latest_block_height) = LightClientConfig::create(server.clone(), dangerous)?;
let lightclient = match seed {
Some(phrase) => Arc::new(LightClient::new_from_phrase(phrase, &config, birthday,0, false)?),
None => {
if config.wallet_exists() {
Arc::new(LightClient::read_from_disk(&config)?)
} else {
println!("Creating a new wallet");
Arc::new(LightClient::new(&config, latest_block_height)?)
}
}
};
// Initialize logging
lightclient.init_logging()?;
// Print startup Messages
info!(""); // Blank line
info!("Starting Silentdragonlite-CLI");
info!("Light Client config {:?}", config);
if print_updates {
println!("Lightclient connecting to {}", config.server);
}
// At startup, run a sync.
if first_sync {
let update = lightclient.do_sync(true);
if print_updates {
match update {
Ok(j) => {
println!("{}", j.pretty(2));
},
Err(e) => println!("{}", e)
}
}
}
// Start the command loop
let (command_tx, resp_rx) = command_loop(lightclient.clone());
Ok((command_tx, resp_rx))
}
pub fn start_interactive(command_tx: Sender<(String, Vec<String>)>, resp_rx: Receiver<String>) {
// `()` can be used when no completer is required
let mut rl = rustyline::Editor::<()>::new();
println!("Ready!");
let send_command = |cmd: String, args: Vec<String>| -> String {
command_tx.send((cmd.clone(), args)).unwrap();
match resp_rx.recv() {
Ok(s) => s,
Err(e) => {
let e = format!("Error executing command {}: {}", cmd, e);
eprintln!("{}", e);
error!("{}", e);
return "".to_string()
}
}
};
let info = send_command("info".to_string(), vec![]);
let chain_name = json::parse(&info).unwrap()["chain_name"].as_str().unwrap().to_string();
loop {
// Read the height first
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') >> ",
chain_name, height));
match readline {
Ok(line) => {
rl.add_history_entry(line.as_str());
// Parse command line arguments
let mut cmd_args = match shellwords::split(&line) {
Ok(args) => args,
Err(_) => {
println!("Mismatched Quotes");
continue;
}
};
if cmd_args.is_empty() {
continue;
}
let cmd = cmd_args.remove(0);
let args: Vec<String> = cmd_args;
println!("{}", send_command(cmd, args));
// Special check for Quit command.
if line == "quit" {
break;
}
},
Err(rustyline::error::ReadlineError::Interrupted) => {
println!("CTRL-C");
info!("CTRL-C");
println!("{}", send_command("save".to_string(), vec![]));
break
},
Err(rustyline::error::ReadlineError::Eof) => {
println!("CTRL-D");
info!("CTRL-D");
println!("{}", send_command("save".to_string(), vec![]));
break
},
Err(err) => {
println!("Error: {:?}", err);
break
}
}
}
}
pub fn command_loop(lightclient: Arc<LightClient>) -> (Sender<(String, Vec<String>)>, Receiver<String>) {
let (command_tx, command_rx) = channel::<(String, Vec<String>)>();
let (resp_tx, resp_rx) = channel::<String>();
let lc = lightclient.clone();
std::thread::spawn(move || {
//start mempool_monitor
match LightClient::start_mempool_monitor(lc.clone()) {
Ok(_) => {},
Err(e) => {
error!("Error starting mempool: {:?}", e);
}
}
loop {
match command_rx.recv_timeout(std::time::Duration::from_secs(5 * 60)) {
Ok((cmd, args)) => {
let args = args.iter().map(|s| s.as_ref()).collect();
let cmd_response = commands::do_user_command(&cmd, &args, lc.as_ref());
resp_tx.send(cmd_response).unwrap();
if cmd == "quit" {
info!("Quit");
break;
}
},
Err(_) => {
// 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");
match lc.do_sync(false) {
Ok(_) => {},
Err(e) => {error!("{}", e)}
}
}
}
}
});
(command_tx, resp_rx)
}
pub fn attempt_recover_seed(password: Option<String>) {
// Create a Light Client Config in an attempt to recover the file.
let config = LightClientConfig {
server: "0.0.0.0:0".parse().unwrap(),
chain_name: "main".to_string(),
sapling_activation_height: 0,
consensus_branch_id: "000000".to_string(),
anchor_offset: 0,
no_cert_verification: false,
data_dir: None,
};
match LightClient::attempt_recover_seed(&config, password) {
Ok(_seed) => println!("Recovered seed "),
Err(e) => eprintln!("Failed to recover seed. Error: {}", e)
};
}

View File

@@ -1,93 +1,93 @@
use silentdragonxlitelib::lightclient::{self, LightClientConfig};
use silentdragonxlite_cli::{configure_clapapp,
report_permission_error,
startup,
start_interactive,
attempt_recover_seed};
//version::VERSION
use log::error;
pub fn main() {
// Get command line arguments
use clap::{App, Arg};
let fresh_app = App::new("SilentDragonXLite CLI");
let configured_app = configure_clapapp!(fresh_app);
let matches = configured_app.get_matches();
if matches.is_present("recover") {
// Create a Light Client Config in an attempt to recover the file.
attempt_recover_seed(matches.value_of("password").map(|s| s.to_string()));
return;
}
let command = matches.value_of("COMMAND");
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 seed = matches.value_of("seed").map(|s| s.to_string());
let maybe_birthday = matches.value_of("birthday");
if seed.is_some() && maybe_birthday.is_none() {
eprintln!("ERROR!");
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.");
return;
}
let birthday = match maybe_birthday.unwrap_or("0").parse::<u64>() {
Ok(b) => b,
Err(e) => {
eprintln!("Couldn't parse birthday. This should be a block number. Error={}", e);
return;
}
};
let server = LightClientConfig::get_server_or_default(maybe_server);
// 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() {
eprintln!("Please provide the --server parameter as [scheme]://[host]:[port].\nYou provided: {}", server);
return;
}
let dangerous = matches.is_present("dangerous");
let nosync = matches.is_present("nosync");
let (command_tx, resp_rx) = match startup(server, dangerous, seed, birthday, !nosync, command.is_none()) {
Ok(c) => c,
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);
eprintln!("{}", emsg);
error!("{}", emsg);
if cfg!(target_os = "unix" ) {
match e.raw_os_error() {
Some(13) => report_permission_error(),
_ => {},
}
};
return;
}
};
if command.is_none() {
start_interactive(command_tx, resp_rx);
} else {
command_tx.send(
(command.unwrap().to_string(),
params.iter().map(|s| s.to_string()).collect::<Vec<String>>()))
.unwrap();
match resp_rx.recv() {
Ok(s) => println!("{}", s),
Err(e) => {
let e = format!("Error executing command {}: {}", command.unwrap(), e);
eprintln!("{}", e);
error!("{}", e);
}
}
// Save before exit
command_tx.send(("save".to_string(), vec![])).unwrap();
resp_rx.recv().unwrap();
}
}
use silentdragonxlitelib::lightclient::{self, LightClientConfig};
use silentdragonxlite_cli::{configure_clapapp,
report_permission_error,
startup,
start_interactive,
attempt_recover_seed};
//version::VERSION
use log::error;
pub fn main() {
// Get command line arguments
use clap::{App, Arg};
let fresh_app = App::new("SilentDragonXLite CLI");
let configured_app = configure_clapapp!(fresh_app);
let matches = configured_app.get_matches();
if matches.is_present("recover") {
// Create a Light Client Config in an attempt to recover the file.
attempt_recover_seed(matches.value_of("password").map(|s| s.to_string()));
return;
}
let command = matches.value_of("COMMAND");
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 seed = matches.value_of("seed").map(|s| s.to_string());
let maybe_birthday = matches.value_of("birthday");
if seed.is_some() && maybe_birthday.is_none() {
eprintln!("ERROR!");
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.");
return;
}
let birthday = match maybe_birthday.unwrap_or("0").parse::<u64>() {
Ok(b) => b,
Err(e) => {
eprintln!("Couldn't parse birthday. This should be a block number. Error={}", e);
return;
}
};
let server = LightClientConfig::get_server_or_default(maybe_server);
// 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() {
eprintln!("Please provide the --server parameter as [scheme]://[host]:[port].\nYou provided: {}", server);
return;
}
let dangerous = matches.is_present("dangerous");
let nosync = matches.is_present("nosync");
let (command_tx, resp_rx) = match startup(server, dangerous, seed, birthday, !nosync, command.is_none()) {
Ok(c) => c,
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);
eprintln!("{}", emsg);
error!("{}", emsg);
if cfg!(target_os = "unix" ) {
match e.raw_os_error() {
Some(13) => report_permission_error(),
_ => {},
}
};
return;
}
};
if command.is_none() {
start_interactive(command_tx, resp_rx);
} else {
command_tx.send(
(command.unwrap().to_string(),
params.iter().map(|s| s.to_string()).collect::<Vec<String>>()))
.unwrap();
match resp_rx.recv() {
Ok(s) => println!("{}", s),
Err(e) => {
let e = format!("Error executing command {}: {}", command.unwrap(), e);
eprintln!("{}", e);
error!("{}", e);
}
}
// Save before exit
command_tx.send(("save".to_string(), vec![])).unwrap();
resp_rx.recv().unwrap();
}
}

View File

@@ -1 +1 @@
pub const VERSION:&str = "1.1.2";
pub const VERSION:&str = "1.1.2";

View File

@@ -1,43 +1,43 @@
FROM ubuntu:16.04
LABEL Description="Rust compile env for Linux + Windows (cross)"
RUN apt update
RUN apt install -y build-essential mingw-w64 gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf curl vim wget
# Get Rust
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
RUN rustup target add x86_64-pc-windows-gnu
RUN rustup target add aarch64-unknown-linux-gnu
RUN rustup target add armv7-unknown-linux-gnueabihf
# Append the linker to the cargo config for Windows cross compile
RUN echo "[target.x86_64-pc-windows-gnu]" >> /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 && \
echo "linker = '/usr/bin/aarch64-linux-gnu-gcc'" >> /root/.cargo/config
RUN echo "[target.armv7-unknown-linux-gnueabihf]" >> /root/.cargo/config && \
echo "linker = '/usr/bin/arm-linux-gnueabihf-gcc'" >> /root/.cargo/config
ENV CC_x86_64_unknown_linux_musl="gcc"
ENV CC_aarch64_unknown_linux_gnu="aarch64-linux-gnu-gcc"
ENV CC_armv7_unknown_linux_gnueabhihf="arm-linux-gnueabihf-gcc"
# 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
# For windows cross compilation, use a pre-build binary. Remember to set the
# SODIUM_LIB_DIR for windows cross compilation
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
RUN apt install -y git
# 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 && \
cd silentdragonlite-light-cli && \
cargo fetch && \
cd /tmp && rm -rf silentdragonlite-light-cli
FROM ubuntu:16.04
LABEL Description="Rust compile env for Linux + Windows (cross)"
RUN apt update
RUN apt install -y build-essential mingw-w64 gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf curl vim wget
# Get Rust
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
RUN rustup target add x86_64-pc-windows-gnu
RUN rustup target add aarch64-unknown-linux-gnu
RUN rustup target add armv7-unknown-linux-gnueabihf
# Append the linker to the cargo config for Windows cross compile
RUN echo "[target.x86_64-pc-windows-gnu]" >> /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 && \
echo "linker = '/usr/bin/aarch64-linux-gnu-gcc'" >> /root/.cargo/config
RUN echo "[target.armv7-unknown-linux-gnueabihf]" >> /root/.cargo/config && \
echo "linker = '/usr/bin/arm-linux-gnueabihf-gcc'" >> /root/.cargo/config
ENV CC_x86_64_unknown_linux_musl="gcc"
ENV CC_aarch64_unknown_linux_gnu="aarch64-linux-gnu-gcc"
ENV CC_armv7_unknown_linux_gnueabhihf="arm-linux-gnueabihf-gcc"
# 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
# For windows cross compilation, use a pre-build binary. Remember to set the
# SODIUM_LIB_DIR for windows cross compilation
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
RUN apt install -y git
# 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 && \
cd silentdragonlite-light-cli && \
cargo fetch && \
cd /tmp && rm -rf silentdragonlite-light-cli

View File

@@ -1,80 +1,80 @@
[package]
name = "silentdragonxlitelib"
version = "0.1.0"
edition = "2018"
[features]
default = ["embed_params"]
embed_params = []
[dependencies]
base58 = "0.1.0"
bs58 = { version = "0.2", features = ["check"] }
log = "0.4"
log4rs = "0.8.3"
dirs = "2.0.2"
http = "0.2"
hex = "0.3"
protobuf = "2"
byteorder = "1"
json = "0.12.0"
tiny-bip39 = "0.6.2"
secp256k1 = "=0.15.0"
sha2 = "0.8.0"
ripemd160 = "0.8.0"
lazy_static = "1.2.0"
rust-embed = { version = "5.1.0", features = ["debug-embed"] }
rand = "0.7.2"
sodiumoxide = "0.2.5"
ring = "0.16.9"
libflate = "0.1"
subtle = "2"
threadpool = "1.8.0"
num_cpus = "1.13.0"
tonic = { version = "0.1.1", features = ["tls", "tls-roots"] }
bytes = "0.4"
prost = "0.6"
prost-types = "0.6"
tokio = { version = "0.2", features = ["rt-threaded", "time", "stream", "fs", "macros", "uds", "full"] }
tokio-rustls = { version = "0.12.1", features = ["dangerous_configuration"] }
webpki = "0.21.0"
webpki-roots = "0.18.0"
[dependencies.bellman]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false
features = ["groth16"]
[dependencies.pairing]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
[dependencies.zcash_client_backend]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false
[dependencies.zcash_primitives]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false
features = ["transparent-inputs"]
[dependencies.zcash_proofs]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false
[dependencies.ff]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
features = ["ff_derive"]
[build-dependencies]
tonic-build = "0.1.1"
[dev-dependencies]
tempdir = "0.3.7"
[package]
name = "silentdragonxlitelib"
version = "0.1.0"
edition = "2018"
[features]
default = ["embed_params"]
embed_params = []
[dependencies]
base58 = "0.1.0"
bs58 = { version = "0.2", features = ["check"] }
log = "0.4"
log4rs = "0.8.3"
dirs = "2.0.2"
http = "0.2"
hex = "0.3"
protobuf = "2"
byteorder = "1"
json = "0.12.0"
tiny-bip39 = "0.6.2"
secp256k1 = "=0.15.0"
sha2 = "0.8.0"
ripemd160 = "0.8.0"
lazy_static = "1.2.0"
rust-embed = { version = "5.1.0", features = ["debug-embed"] }
rand = "0.7.2"
sodiumoxide = "0.2.5"
ring = "0.16.9"
libflate = "0.1"
subtle = "2"
threadpool = "1.8.0"
num_cpus = "1.13.0"
tonic = { version = "0.1.1", features = ["tls", "tls-roots"] }
bytes = "0.4"
prost = "0.6"
prost-types = "0.6"
tokio = { version = "0.2", features = ["rt-threaded", "time", "stream", "fs", "macros", "uds", "full"] }
tokio-rustls = { version = "0.12.1", features = ["dangerous_configuration"] }
webpki = "0.21.0"
webpki-roots = "0.18.0"
[dependencies.bellman]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false
features = ["groth16"]
[dependencies.pairing]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
[dependencies.zcash_client_backend]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false
[dependencies.zcash_primitives]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false
features = ["transparent-inputs"]
[dependencies.zcash_proofs]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
default-features = false
[dependencies.ff]
git = "https://git.hush.is/hush/librustzcash.git"
rev= "acff1444ec373e9c3e37b47ca95bfd358e45255b"
features = ["ff_derive"]
[build-dependencies]
tonic-build = "0.1.1"
[dev-dependencies]
tempdir = "0.3.7"

View File

@@ -1,13 +1,13 @@
// Copyright The Hush Developers 2019-2022
// Released under the GPLv3
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::configure()
.build_server(false)
.compile(
&["proto/service.proto", "proto/compact_formats.proto"],
&["proto"],
)?;
println!("cargo:rerun-if-changed=proto/service.proto");
Ok(())
}
// Copyright The Hush Developers 2019-2022
// Released under the GPLv3
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::configure()
.build_server(false)
.compile(
&["proto/service.proto", "proto/compact_formats.proto"],
&["proto"],
)?;
println!("cargo:rerun-if-changed=proto/service.proto");
Ok(())
}

View File

@@ -1,65 +1,65 @@
syntax = "proto3";
package cash.z.wallet.sdk.rpc;
option go_package = "lightwalletd/walletrpc";
option swift_prefix = "";
// 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.
// CompactBlock is a packaging of ONLY the data from a block that's needed to:
// 1. Detect a payment to your shielded Sapling address
// 2. Detect a spend of your shielded Sapling notes
// 3. Update your witnesses to generate new Sapling spend proofs.
message CompactBlock {
uint32 protoVersion = 1; // the version of this wire format, for storage
uint64 height = 2; // the height of this block
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
uint32 time = 5; // Unix epoch time when the block was mined
bytes header = 6; // (hash, prevHash, and time) OR (full header)
repeated CompactTx vtx = 7; // compact transactions from this block
}
message CompactTx {
// Index and hash will allow the receiver to call out to chain
// explorers or other data structures to retrieve more information
// about this transaction.
uint64 index = 1; // the index within the full block
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
// stateless server and a transaction with transparent inputs, this will be
// unset because the calculation requires reference to prior transactions.
// in a pure-Sapling context, the fee will be calculable as:
// valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut))
uint32 fee = 3;
repeated CompactSaplingSpend spends = 4;
repeated CompactSaplingOutput outputs = 5;
}
// CompactSaplingSpend is a Sapling Spend Description as described in 7.3 of the Zcash
// protocol specification.
message CompactSaplingSpend {
bytes nf = 1; // nullifier (see the Zcash protocol specification)
}
// output is a Sapling Output Description as described in section 7.4 of the
// Zcash protocol spec. Total size is 948.
message CompactSaplingOutput {
bytes cmu = 1; // note commitment u-coordinate
bytes epk = 2; // ephemeral public key
bytes ciphertext = 3; // first 52 bytes of ciphertext
}
/*
message CompactSpend {
bytes nf = 1; // nullifier (see the Zcash protocol specification)
}
message CompactOutput {
bytes cmu = 1; // note commitment u-coordinate
bytes epk = 2; // ephemeral public key
bytes ciphertext = 3; // first 52 bytes of ciphertext
}
*/
syntax = "proto3";
package cash.z.wallet.sdk.rpc;
option go_package = "lightwalletd/walletrpc";
option swift_prefix = "";
// 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.
// CompactBlock is a packaging of ONLY the data from a block that's needed to:
// 1. Detect a payment to your shielded Sapling address
// 2. Detect a spend of your shielded Sapling notes
// 3. Update your witnesses to generate new Sapling spend proofs.
message CompactBlock {
uint32 protoVersion = 1; // the version of this wire format, for storage
uint64 height = 2; // the height of this block
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
uint32 time = 5; // Unix epoch time when the block was mined
bytes header = 6; // (hash, prevHash, and time) OR (full header)
repeated CompactTx vtx = 7; // compact transactions from this block
}
message CompactTx {
// Index and hash will allow the receiver to call out to chain
// explorers or other data structures to retrieve more information
// about this transaction.
uint64 index = 1; // the index within the full block
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
// stateless server and a transaction with transparent inputs, this will be
// unset because the calculation requires reference to prior transactions.
// in a pure-Sapling context, the fee will be calculable as:
// valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut))
uint32 fee = 3;
repeated CompactSaplingSpend spends = 4;
repeated CompactSaplingOutput outputs = 5;
}
// CompactSaplingSpend is a Sapling Spend Description as described in 7.3 of the Zcash
// protocol specification.
message CompactSaplingSpend {
bytes nf = 1; // nullifier (see the Zcash protocol specification)
}
// output is a Sapling Output Description as described in section 7.4 of the
// Zcash protocol spec. Total size is 948.
message CompactSaplingOutput {
bytes cmu = 1; // note commitment u-coordinate
bytes epk = 2; // ephemeral public key
bytes ciphertext = 3; // first 52 bytes of ciphertext
}
/*
message CompactSpend {
bytes nf = 1; // nullifier (see the Zcash protocol specification)
}
message CompactOutput {
bytes cmu = 1; // note commitment u-coordinate
bytes epk = 2; // ephemeral public key
bytes ciphertext = 3; // first 52 bytes of ciphertext
}
*/

View File

@@ -1,170 +1,170 @@
syntax = "proto3";
package cash.z.wallet.sdk.rpc;
option go_package = "lightwalletd/walletrpc";
option swift_prefix = "";
import "compact_formats.proto";
// A BlockID message contains identifiers to select a block: a height or a
// hash. If the hash is present it takes precedence.
message BlockID {
uint64 height = 1;
bytes hash = 2;
}
// 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
// it. Further permutations are left as an exercise.
message BlockRange {
BlockID start = 1;
BlockID end = 2;
}
// A TxFilter contains the information needed to identify a particular
// transaction: either a block and an index, or a direct transaction hash.
message TxFilter {
BlockID block = 1;
uint64 index = 2;
bytes hash = 3;
}
// RawTransaction contains the complete transaction data. It also optionally includes
// the block height in which the transaction was included
message RawTransaction {
bytes data = 1;
uint64 height = 2;
}
message SendResponse {
int32 errorCode = 1;
string errorMessage = 2;
}
// Empty placeholder. Someday we may want to specify e.g. a particular chain fork.
message ChainSpec {}
message Empty {}
message LightdInfo {
string version = 1;
string vendor = 2;
bool taddrSupport = 3;
string chainName = 4;
uint64 saplingActivationHeight = 5;
string consensusBranchId = 6; // This should really be u32 or []byte, but string for readability
uint64 blockHeight = 7;
uint64 difficulty = 8;
uint64 longestchain = 9;
uint64 notarized = 10;
}
message Coinsupply {
string result = 1;
string coin = 2;
uint64 height = 3;
uint64 supply = 4;
uint64 zfunds = 5;
uint64 total = 6;
}
message TransparentAddress {
string address = 1;
}
message TransparentAddressBlockFilter {
string address = 1;
BlockRange range = 2;
}
message Address {
string address = 1;
}
message AddressList {
repeated string addresses = 1;
}
message Balance {
int64 valueZat = 1;
}
message Exclude {
repeated bytes txid = 1;
}
// The TreeState is derived from the Hush getblockmerkletree rpc.
// https://faq.hush.is/rpc/getblockmerkletree.html
message TreeState {
string network = 1; // "main" or "test"
uint64 height = 2; // block height
string hash = 3; // block id
uint32 time = 4; // Unix epoch time when the block was mined
string saplingTree = 5; // sapling commitment tree state
}
// Results are sorted by height, which makes it easy to issue another
// request that picks up from where the previous left off.
message GetAddressUtxosArg {
repeated string addresses = 1;
uint64 startHeight = 2;
uint32 maxEntries = 3; // zero means unlimited
}
message GetAddressUtxosReply {
string address = 6;
bytes txid = 1;
int32 index = 2;
bytes script = 3;
int64 valueZat = 4;
uint64 height = 5;
}
message GetAddressUtxosReplyList {
repeated GetAddressUtxosReply addressUtxos = 1;
}
service CompactTxStreamer {
// Return the height of the tip of the best chain
rpc GetLatestBlock(ChainSpec) returns (BlockID) {}
// Return the compact block corresponding to the given block identifier
rpc GetBlock(BlockID) returns (CompactBlock) {}
// Return a list of consecutive compact blocks
rpc GetBlockRange(BlockRange) returns (stream CompactBlock) {}
// Return the requested full (not compact) transaction (as from zcashd)
rpc GetTransaction(TxFilter) returns (RawTransaction) {}
// Submit the given transaction to the Zcash network
rpc SendTransaction(RawTransaction) returns (SendResponse) {}
// Return the txids corresponding to the given t-address within the given block range
rpc GetTaddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {}
// wrapper for GetTaddressTxids
rpc GetAddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {}
rpc GetTaddressBalance(AddressList) returns (Balance) {}
rpc GetTaddressBalanceStream(stream Address) returns (Balance) {}
// 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
// all transactions; otherwise return all *except* those in the Exclude list
// (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
// 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
// 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.
rpc GetMempoolTx(Exclude) returns (stream CompactTx) {}
// 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.
rpc GetMempoolStream(Empty) returns (stream RawTransaction) {}
// 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
// values also (even though they can be obtained using GetBlock).
// The block can be specified by either height or hash.
rpc GetTreeState(BlockID) returns (TreeState) {}
rpc GetLatestTreeState(Empty) returns (TreeState) {}
rpc GetAddressUtxos(GetAddressUtxosArg) returns (GetAddressUtxosReplyList) {}
rpc GetAddressUtxosStream(GetAddressUtxosArg) returns (stream GetAddressUtxosReply) {}
// Return information about this lightwalletd instance and the blockchain
rpc GetLightdInfo(Empty) returns (LightdInfo) {}
// Testing-only, requires lightwalletd --ping-very-insecure (do not enable in production)
// rpc Ping(Duration) returns (PingResponse) {}
rpc GetCoinsupply(Empty) returns (Coinsupply) {}
syntax = "proto3";
package cash.z.wallet.sdk.rpc;
option go_package = "lightwalletd/walletrpc";
option swift_prefix = "";
import "compact_formats.proto";
// A BlockID message contains identifiers to select a block: a height or a
// hash. If the hash is present it takes precedence.
message BlockID {
uint64 height = 1;
bytes hash = 2;
}
// 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
// it. Further permutations are left as an exercise.
message BlockRange {
BlockID start = 1;
BlockID end = 2;
}
// A TxFilter contains the information needed to identify a particular
// transaction: either a block and an index, or a direct transaction hash.
message TxFilter {
BlockID block = 1;
uint64 index = 2;
bytes hash = 3;
}
// RawTransaction contains the complete transaction data. It also optionally includes
// the block height in which the transaction was included
message RawTransaction {
bytes data = 1;
uint64 height = 2;
}
message SendResponse {
int32 errorCode = 1;
string errorMessage = 2;
}
// Empty placeholder. Someday we may want to specify e.g. a particular chain fork.
message ChainSpec {}
message Empty {}
message LightdInfo {
string version = 1;
string vendor = 2;
bool taddrSupport = 3;
string chainName = 4;
uint64 saplingActivationHeight = 5;
string consensusBranchId = 6; // This should really be u32 or []byte, but string for readability
uint64 blockHeight = 7;
uint64 difficulty = 8;
uint64 longestchain = 9;
uint64 notarized = 10;
}
message Coinsupply {
string result = 1;
string coin = 2;
uint64 height = 3;
uint64 supply = 4;
uint64 zfunds = 5;
uint64 total = 6;
}
message TransparentAddress {
string address = 1;
}
message TransparentAddressBlockFilter {
string address = 1;
BlockRange range = 2;
}
message Address {
string address = 1;
}
message AddressList {
repeated string addresses = 1;
}
message Balance {
int64 valueZat = 1;
}
message Exclude {
repeated bytes txid = 1;
}
// The TreeState is derived from the Hush getblockmerkletree rpc.
// https://faq.hush.is/rpc/getblockmerkletree.html
message TreeState {
string network = 1; // "main" or "test"
uint64 height = 2; // block height
string hash = 3; // block id
uint32 time = 4; // Unix epoch time when the block was mined
string saplingTree = 5; // sapling commitment tree state
}
// Results are sorted by height, which makes it easy to issue another
// request that picks up from where the previous left off.
message GetAddressUtxosArg {
repeated string addresses = 1;
uint64 startHeight = 2;
uint32 maxEntries = 3; // zero means unlimited
}
message GetAddressUtxosReply {
string address = 6;
bytes txid = 1;
int32 index = 2;
bytes script = 3;
int64 valueZat = 4;
uint64 height = 5;
}
message GetAddressUtxosReplyList {
repeated GetAddressUtxosReply addressUtxos = 1;
}
service CompactTxStreamer {
// Return the height of the tip of the best chain
rpc GetLatestBlock(ChainSpec) returns (BlockID) {}
// Return the compact block corresponding to the given block identifier
rpc GetBlock(BlockID) returns (CompactBlock) {}
// Return a list of consecutive compact blocks
rpc GetBlockRange(BlockRange) returns (stream CompactBlock) {}
// Return the requested full (not compact) transaction (as from zcashd)
rpc GetTransaction(TxFilter) returns (RawTransaction) {}
// Submit the given transaction to the Zcash network
rpc SendTransaction(RawTransaction) returns (SendResponse) {}
// Return the txids corresponding to the given t-address within the given block range
rpc GetTaddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {}
// wrapper for GetTaddressTxids
rpc GetAddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {}
rpc GetTaddressBalance(AddressList) returns (Balance) {}
rpc GetTaddressBalanceStream(stream Address) returns (Balance) {}
// 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
// all transactions; otherwise return all *except* those in the Exclude list
// (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
// 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
// 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.
rpc GetMempoolTx(Exclude) returns (stream CompactTx) {}
// 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.
rpc GetMempoolStream(Empty) returns (stream RawTransaction) {}
// 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
// values also (even though they can be obtained using GetBlock).
// The block can be specified by either height or hash.
rpc GetTreeState(BlockID) returns (TreeState) {}
rpc GetLatestTreeState(Empty) returns (TreeState) {}
rpc GetAddressUtxos(GetAddressUtxosArg) returns (GetAddressUtxosReplyList) {}
rpc GetAddressUtxosStream(GetAddressUtxosArg) returns (stream GetAddressUtxosReply) {}
// Return information about this lightwalletd instance and the blockchain
rpc GetLightdInfo(Empty) returns (LightdInfo) {}
// Testing-only, requires lightwalletd --ping-very-insecure (do not enable in production)
// rpc Ping(Duration) returns (PingResponse) {}
rpc GetCoinsupply(Empty) returns (Coinsupply) {}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,366 +1,363 @@
// Copyright The Hush Developers 2019-2022
// Released under the GPLv3
use log::{info,error};
use std::sync::Arc;
use zcash_primitives::transaction::{TxId};
use crate::grpc_client::{ChainSpec, BlockId, BlockRange, RawTransaction, CompactBlock,
TransparentAddressBlockFilter, TxFilter, Empty, LightdInfo, Coinsupply};
use tonic::transport::{Channel, ClientTlsConfig};
use tokio_rustls::{rustls::ClientConfig};
use tonic::{Request};
use threadpool::ThreadPool;
use std::sync::mpsc::channel;
use crate::PubCertificate;
use crate::grpc_client::compact_tx_streamer_client::CompactTxStreamerClient;
mod danger {
use tokio_rustls::rustls;
use webpki;
pub struct NoCertificateVerification {}
impl rustls::ServerCertVerifier for NoCertificateVerification {
fn verify_server_cert(&self,
_roots: &rustls::RootCertStore,
_presented_certs: &[rustls::Certificate],
_dns_name: webpki::DNSNameRef<'_>,
_ocsp: &[u8]) -> Result<rustls::ServerCertVerified, rustls::TLSError> {
Ok(rustls::ServerCertVerified::assertion())
}
}
}
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") {
Channel::builder(uri.clone()).connect().await?
} else {
let mut config = ClientConfig::new();
config.alpn_protocols.push(b"h2".to_vec());
config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
config.root_store.add_pem_file(
&mut PubCertificate::get("lightwalletd-lite.myhush.pem").unwrap().as_ref()).unwrap();
if no_cert {
config.dangerous()
.set_certificate_verifier(Arc::new(danger::NoCertificateVerification {}));
}
let tls = ClientTlsConfig::new()
.rustls_client_config(config)
.domain_name(uri.host().unwrap());
Channel::builder(uri.clone())
.tls_config(tls)
.connect()
.await?
};
Ok(CompactTxStreamerClient::new(channel))
}
// ==============
// GRPC code
// ==============
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 request = Request::new(Empty {});
let response = client.get_lightd_info(request).await?;
Ok(response.into_inner())
}
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())?;
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>> {
let mut client = get_client(uri, no_cert).await?;
let request = Request::new(Empty {});
let response = client.get_coinsupply(request).await?;
Ok(response.into_inner())
}
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())?;
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>(
uri: &http::Uri,
start_height: u64,
end_height: u64,
no_cert: bool,
pool: ThreadPool,
c: F
) -> Result<(), Box<dyn std::error::Error>>
where F : Fn(&[u8], u64) {
let mut client = get_client(uri, no_cert).await?;
let bs = BlockId { height: start_height, hash: vec![] };
let be = BlockId { height: end_height, hash: vec![] };
let request = Request::new(BlockRange { start: Some(bs), end: Some(be) });
let (tx, rx) = channel::<Option<CompactBlock>>();
let (ftx, frx) = channel();
pool.execute(move || {
while let Ok(Some(block)) = rx.recv() {
use prost::Message;
let mut encoded_buf = vec![];
if let Err(e) = block.encode(&mut encoded_buf) {
error!("Error encoding block: {:?}", e);
break;
}
c(&encoded_buf, block.height);
}
if let Err(e) = ftx.send(Ok(())) {
error!("Error sending completion signal: {:?}", e);
}
});
let mut response = client.get_block_range(request).await?.into_inner();
while let Some(block) = response.message().await? {
if let Err(e) = tx.send(Some(block)) {
error!("Error sending block to channel: {:?}", e);
break;
}
}
if let Err(e) = tx.send(None) {
error!("Error sending end signal to channel: {:?}", e);
}
frx.iter().take(1).collect::<Result<Vec<()>, String>>()?;
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>
where F : Fn(&[u8], u64) {
let mut rt = match tokio::runtime::Runtime::new() {
Ok(r) => r,
Err(e) => {
let es = format!("Error creating runtime {:?}", e);
error!("{}", es);
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) => {
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,
address: String,
start_height: u64,
end_height: u64,
no_cert: bool,
c: F
) -> Result<(), Box<dyn std::error::Error>>
where F : Fn(&[u8], u64) {
let mut client = match get_client(uri, no_cert).await {
Ok(client) => client,
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 request = Request::new(TransparentAddressBlockFilter{ address, range: Some(BlockRange{ start, end }) });
let maybe_response = match client.get_address_txids(request).await {
Ok(response) => response,
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? {
c(&tx.data, tx.height);
}
Ok(())
}
// function to monitor mempool transactions
pub async fn monitor_mempool<F: 'static + std::marker::Send>(
uri: &http::Uri,
no_cert: bool,
mut c: F
) -> 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 request = Request::new(Empty {});
let mut response = client
.get_mempool_stream(request)
.await
.map_err(|e| format!("{}", e))?
.into_inner();
while let Ok(Some(rtx)) = response.message().await {
if let Err(e) = c(rtx) {
info!("Error processing RawTransaction: {:?}", e);
}
}
Ok(())
}
pub fn fetch_transparent_txids<F : 'static + std::marker::Send>(
uri: &http::Uri,
address: String,
start_height: u64,
end_height: u64,
no_cert: bool,
c: F
) -> Result<(), String>
where F : Fn(&[u8], u64) {
let mut rt = match tokio::runtime::Runtime::new() {
Ok(r) => r,
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) => {
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>> {
let mut client = get_client(uri, no_cert).await?;
let request = Request::new(TxFilter { block: None, index: 0, hash: txid.0.to_vec() });
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,
Err(e) => {
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) => {
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?;
let request = Request::new(RawTransaction {data: tx_bytes.to_vec(), height: 0});
let response = client.send_transaction(request).await?;
let sendresponse = response.into_inner();
if sendresponse.error_code == 0 {
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)))
}
}
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())?;
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?;
let request = Request::new(ChainSpec {});
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,
Err(e) => {
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);
errstr
})
}
// Copyright The Hush Developers 2019-2022
// Released under the GPLv3
use log::{info,error};
use std::sync::Arc;
use zcash_primitives::transaction::{TxId};
use crate::grpc_client::{ChainSpec, BlockId, BlockRange, RawTransaction, CompactBlock,
TransparentAddressBlockFilter, TxFilter, Empty, LightdInfo, Coinsupply};
use tonic::transport::{Channel, ClientTlsConfig};
use tokio_rustls::{rustls::ClientConfig};
use tonic::{Request};
use threadpool::ThreadPool;
use std::sync::mpsc::channel;
use crate::PubCertificate;
use crate::grpc_client::compact_tx_streamer_client::CompactTxStreamerClient;
mod danger {
use tokio_rustls::rustls;
use webpki;
pub struct NoCertificateVerification {}
impl rustls::ServerCertVerifier for NoCertificateVerification {
fn verify_server_cert(&self,
_roots: &rustls::RootCertStore,
_presented_certs: &[rustls::Certificate],
_dns_name: webpki::DNSNameRef<'_>,
_ocsp: &[u8]) -> Result<rustls::ServerCertVerified, rustls::TLSError> {
Ok(rustls::ServerCertVerified::assertion())
}
}
}
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") {
Channel::builder(uri.clone()).connect().await?
} else {
let mut config = ClientConfig::new();
config.alpn_protocols.push(b"h2".to_vec());
config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
config.root_store.add_pem_file(
&mut PubCertificate::get("lightwalletd-lite.myhush.pem").unwrap().as_ref()).unwrap();
if no_cert {
config.dangerous()
.set_certificate_verifier(Arc::new(danger::NoCertificateVerification {}));
}
let tls = ClientTlsConfig::new()
.rustls_client_config(config)
.domain_name(uri.host().unwrap());
Channel::builder(uri.clone())
.tls_config(tls)
.connect()
.await?
};
Ok(CompactTxStreamerClient::new(channel))
}
// ==============
// GRPC code
// ==============
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 request = Request::new(Empty {});
let response = client.get_lightd_info(request).await?;
Ok(response.into_inner())
}
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())?;
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>> {
let mut client = get_client(uri, no_cert).await?;
let request = Request::new(Empty {});
let response = client.get_coinsupply(request).await?;
Ok(response.into_inner())
}
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())?;
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>(
uri: &http::Uri,
start_height: u64,
end_height: u64,
no_cert: bool,
pool: ThreadPool,
c: F
) -> Result<(), Box<dyn std::error::Error>>
where F : Fn(&[u8], u64) {
let mut client = get_client(uri, no_cert).await?;
let bs = BlockId { height: start_height, hash: vec![] };
let be = BlockId { height: end_height, hash: vec![] };
let request = Request::new(BlockRange { start: Some(bs), end: Some(be) });
let (tx, rx) = channel::<Option<CompactBlock>>();
let (ftx, frx) = channel();
pool.execute(move || {
while let Ok(Some(block)) = rx.recv() {
use prost::Message;
let mut encoded_buf = vec![];
if let Err(e) = block.encode(&mut encoded_buf) {
error!("Error encoding block: {:?}", e);
break;
}
c(&encoded_buf, block.height);
}
if let Err(e) = ftx.send(Ok(())) {
error!("Error sending completion signal: {:?}", e);
}
});
let mut response = client.get_block_range(request).await?.into_inner();
while let Some(block) = response.message().await? {
if let Err(e) = tx.send(Some(block)) {
error!("Error sending block to channel: {:?}", e);
break;
}
}
if let Err(e) = tx.send(None) {
error!("Error sending end signal to channel: {:?}", e);
}
frx.iter().take(1).collect::<Result<Vec<()>, String>>()?;
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>
where F : Fn(&[u8], u64) {
let mut rt = tokio::runtime::Runtime::new().map_err(|e| format!("Error creating runtime {:?}", e))?;
fetch_blocks_with_runtime(&mut rt, uri, start_height, end_height, no_cert, pool, c)
}
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>
where F : Fn(&[u8], u64) {
match rt.block_on(get_block_range(uri, start_height, end_height, no_cert, pool, c)) {
Ok(o) => Ok(o),
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,
address: String,
start_height: u64,
end_height: u64,
no_cert: bool,
c: F
) -> Result<(), Box<dyn std::error::Error>>
where F : Fn(&[u8], u64) {
let mut client = match get_client(uri, no_cert).await {
Ok(client) => client,
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 request = Request::new(TransparentAddressBlockFilter{ address, range: Some(BlockRange{ start, end }) });
let maybe_response = match client.get_address_txids(request).await {
Ok(response) => response,
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? {
c(&tx.data, tx.height);
}
Ok(())
}
// function to monitor mempool transactions
pub async fn monitor_mempool<F: 'static + std::marker::Send>(
uri: &http::Uri,
no_cert: bool,
mut c: F
) -> 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 request = Request::new(Empty {});
let mut response = client
.get_mempool_stream(request)
.await
.map_err(|e| format!("{}", e))?
.into_inner();
while let Ok(Some(rtx)) = response.message().await {
if let Err(e) = c(rtx) {
info!("Error processing RawTransaction: {:?}", e);
}
}
Ok(())
}
pub fn fetch_transparent_txids<F : 'static + std::marker::Send>(
uri: &http::Uri,
address: String,
start_height: u64,
end_height: u64,
no_cert: bool,
c: F
) -> Result<(), String>
where F : Fn(&[u8], u64) {
let mut rt = match tokio::runtime::Runtime::new() {
Ok(r) => r,
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) => {
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>> {
let mut client = get_client(uri, no_cert).await?;
let request = Request::new(TxFilter { block: None, index: 0, hash: txid.0.to_vec() });
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,
Err(e) => {
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) => {
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?;
let request = Request::new(RawTransaction {data: tx_bytes.to_vec(), height: 0});
let response = client.send_transaction(request).await?;
let sendresponse = response.into_inner();
if sendresponse.error_code == 0 {
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)))
}
}
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())?;
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?;
let request = Request::new(ChainSpec {});
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,
Err(e) => {
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);
errstr
})
}

View File

@@ -1,25 +1,25 @@
// Copyright The Hush Developers 2019-2022
// Released under the GPLv3
#[macro_use]
extern crate rust_embed;
pub mod lightclient;
pub mod grpcconnector;
pub mod lightwallet;
pub mod commands;
#[cfg(feature = "embed_params")]
#[derive(RustEmbed)]
#[folder = "zcash-params/"]
pub struct SaplingParams;
#[derive(RustEmbed)]
#[folder = "res/"]
pub struct PubCertificate;
pub const ANCHOR_OFFSET: u32 = 0;
pub mod grpc_client {
tonic::include_proto!("cash.z.wallet.sdk.rpc");
}
// Copyright The Hush Developers 2019-2022
// Released under the GPLv3
#[macro_use]
extern crate rust_embed;
pub mod lightclient;
pub mod grpcconnector;
pub mod lightwallet;
pub mod commands;
#[cfg(feature = "embed_params")]
#[derive(RustEmbed)]
#[folder = "zcash-params/"]
pub struct SaplingParams;
#[derive(RustEmbed)]
#[folder = "res/"]
pub struct PubCertificate;
pub const ANCHOR_OFFSET: u32 = 0;
pub mod grpc_client {
tonic::include_proto!("cash.z.wallet.sdk.rpc");
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +1,46 @@
//! Structs for handling supported address types.
use pairing::bls12_381::Bls12;
use zcash_primitives::primitives::PaymentAddress;
use zcash_client_backend::encoding::{decode_payment_address, decode_transparent_address};
use zcash_primitives::legacy::TransparentAddress;
/// An address that funds can be sent to.
pub enum RecipientAddress {
Shielded(PaymentAddress<Bls12>),
Transparent(TransparentAddress),
}
impl From<PaymentAddress<Bls12>> for RecipientAddress {
fn from(addr: PaymentAddress<Bls12>) -> Self {
RecipientAddress::Shielded(addr)
}
}
impl From<TransparentAddress> for RecipientAddress {
fn from(addr: TransparentAddress) -> Self {
RecipientAddress::Transparent(addr)
}
}
impl RecipientAddress {
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
if let Some(pa) = match decode_payment_address(hrp_sapling_address, s) {
Ok(ret) => ret,
Err(_) => None
}
{
Some(RecipientAddress::Shielded(pa)) // Matched a shielded address
} else if let Some(addr) = match decode_transparent_address(
&b58_pubkey_address, &b58_script_address, s) {
Ok(ret) => ret,
Err(_) => None
}
{
Some(RecipientAddress::Transparent(addr)) // Matched a transparent address
} else {
None // Didn't match anything
}
}
}
//! Structs for handling supported address types.
use pairing::bls12_381::Bls12;
use zcash_primitives::primitives::PaymentAddress;
use zcash_client_backend::encoding::{decode_payment_address, decode_transparent_address};
use zcash_primitives::legacy::TransparentAddress;
/// An address that funds can be sent to.
pub enum RecipientAddress {
Shielded(PaymentAddress<Bls12>),
Transparent(TransparentAddress),
}
impl From<PaymentAddress<Bls12>> for RecipientAddress {
fn from(addr: PaymentAddress<Bls12>) -> Self {
RecipientAddress::Shielded(addr)
}
}
impl From<TransparentAddress> for RecipientAddress {
fn from(addr: TransparentAddress) -> Self {
RecipientAddress::Transparent(addr)
}
}
impl RecipientAddress {
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
if let Some(pa) = match decode_payment_address(hrp_sapling_address, s) {
Ok(ret) => ret,
Err(_) => None
}
{
Some(RecipientAddress::Shielded(pa)) // Matched a shielded address
} else if let Some(addr) = match decode_transparent_address(
&b58_pubkey_address, &b58_script_address, s) {
Ok(ret) => ret,
Err(_) => None
}
{
Some(RecipientAddress::Transparent(addr)) // Matched a transparent address
} else {
None // Didn't match anything
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,126 +1,126 @@
use ring::{
hmac::{self, Context, Key},
};
use lazy_static::lazy_static;
use secp256k1::{PublicKey, Secp256k1, SecretKey, SignOnly, VerifyOnly, Error};
lazy_static! {
static ref SECP256K1_SIGN_ONLY: Secp256k1<SignOnly> = Secp256k1::signing_only();
static ref SECP256K1_VERIFY_ONLY: Secp256k1<VerifyOnly> = Secp256k1::verification_only();
}
/// Random entropy, part of extended key.
type ChainCode = Vec<u8>;
const HARDENED_KEY_START_INDEX: u32 = 2_147_483_648; // 2 ** 31
/// KeyIndex indicates the key type and index of a child key.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum KeyIndex {
/// Normal key, index range is from 0 to 2 ** 31 - 1
Normal(u32),
/// Hardened key, index range is from 2 ** 31 to 2 ** 32 - 1
Hardened(u32),
}
impl KeyIndex {
/// Check index range.
pub fn is_valid(self) -> bool {
match self {
KeyIndex::Normal(i) => i < HARDENED_KEY_START_INDEX,
KeyIndex::Hardened(i) => i >= HARDENED_KEY_START_INDEX,
}
}
/// Generate Hardened KeyIndex from normalize index value.
pub fn hardened_from_normalize_index(i: u32) -> Result<KeyIndex, Error> {
if i < HARDENED_KEY_START_INDEX {
Ok(KeyIndex::Hardened(HARDENED_KEY_START_INDEX + i))
} else {
Ok(KeyIndex::Hardened(i))
}
}
/// Generate KeyIndex from raw index value.
pub fn from_index(i: u32) -> Result<Self, Error> {
if i < HARDENED_KEY_START_INDEX {
Ok(KeyIndex::Normal(i))
} else {
Ok(KeyIndex::Hardened(i))
}
}
}
impl From<u32> for KeyIndex {
fn from(index: u32) -> Self {
KeyIndex::from_index(index).expect("KeyIndex")
}
}
/// ExtendedPrivKey is used for child key derivation.
/// See [secp256k1 crate documentation](https://docs.rs/secp256k1) for SecretKey signatures usage.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtendedPrivKey {
pub private_key: SecretKey,
pub chain_code: ChainCode,
}
impl ExtendedPrivKey {
/// Generate an ExtendedPrivKey from seed
pub fn with_seed(seed: &[u8]) -> Result<ExtendedPrivKey, Error> {
let signature = {
let signing_key = Key::new(hmac::HMAC_SHA512, b"Bitcoin seed");
let mut h = Context::with_key(&signing_key);
h.update(&seed);
h.sign()
};
let sig_bytes = signature.as_ref();
let (key, chain_code) = sig_bytes.split_at(sig_bytes.len() / 2);
let private_key = SecretKey::from_slice(key)?;
Ok(ExtendedPrivKey {
private_key,
chain_code: chain_code.to_vec(),
})
}
fn sign_hardended_key(&self, index: u32) -> ring::hmac::Tag {
let signing_key = Key::new(hmac::HMAC_SHA512, &self.chain_code);
let mut h = Context::with_key(&signing_key);
h.update(&[0x00]);
h.update(&self.private_key[..]);
h.update(&index.to_be_bytes());
h.sign()
}
fn sign_normal_key(&self, index: u32) -> ring::hmac::Tag {
let signing_key = Key::new(hmac::HMAC_SHA512, &self.chain_code);
let mut h = Context::with_key(&signing_key);
let public_key = PublicKey::from_secret_key(&SECP256K1_SIGN_ONLY, &self.private_key);
h.update(&public_key.serialize());
h.update(&index.to_be_bytes());
h.sign()
}
/// Derive a child key from ExtendedPrivKey.
pub fn derive_private_key(&self, key_index: KeyIndex) -> Result<ExtendedPrivKey, Error> {
if !key_index.is_valid() {
return Err(Error::InvalidTweak);
}
let signature = match key_index {
KeyIndex::Hardened(index) => self.sign_hardended_key(index),
KeyIndex::Normal(index) => self.sign_normal_key(index),
};
let sig_bytes = signature.as_ref();
let (key, chain_code) = sig_bytes.split_at(sig_bytes.len() / 2);
let mut private_key = SecretKey::from_slice(key)?;
private_key.add_assign(&self.private_key[..])?;
Ok(ExtendedPrivKey {
private_key,
chain_code: chain_code.to_vec(),
})
}
}
use ring::{
hmac::{self, Context, Key},
};
use lazy_static::lazy_static;
use secp256k1::{PublicKey, Secp256k1, SecretKey, SignOnly, VerifyOnly, Error};
lazy_static! {
static ref SECP256K1_SIGN_ONLY: Secp256k1<SignOnly> = Secp256k1::signing_only();
static ref SECP256K1_VERIFY_ONLY: Secp256k1<VerifyOnly> = Secp256k1::verification_only();
}
/// Random entropy, part of extended key.
type ChainCode = Vec<u8>;
const HARDENED_KEY_START_INDEX: u32 = 2_147_483_648; // 2 ** 31
/// KeyIndex indicates the key type and index of a child key.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum KeyIndex {
/// Normal key, index range is from 0 to 2 ** 31 - 1
Normal(u32),
/// Hardened key, index range is from 2 ** 31 to 2 ** 32 - 1
Hardened(u32),
}
impl KeyIndex {
/// Check index range.
pub fn is_valid(self) -> bool {
match self {
KeyIndex::Normal(i) => i < HARDENED_KEY_START_INDEX,
KeyIndex::Hardened(i) => i >= HARDENED_KEY_START_INDEX,
}
}
/// Generate Hardened KeyIndex from normalize index value.
pub fn hardened_from_normalize_index(i: u32) -> Result<KeyIndex, Error> {
if i < HARDENED_KEY_START_INDEX {
Ok(KeyIndex::Hardened(HARDENED_KEY_START_INDEX + i))
} else {
Ok(KeyIndex::Hardened(i))
}
}
/// Generate KeyIndex from raw index value.
pub fn from_index(i: u32) -> Result<Self, Error> {
if i < HARDENED_KEY_START_INDEX {
Ok(KeyIndex::Normal(i))
} else {
Ok(KeyIndex::Hardened(i))
}
}
}
impl From<u32> for KeyIndex {
fn from(index: u32) -> Self {
KeyIndex::from_index(index).expect("KeyIndex")
}
}
/// ExtendedPrivKey is used for child key derivation.
/// See [secp256k1 crate documentation](https://docs.rs/secp256k1) for SecretKey signatures usage.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtendedPrivKey {
pub private_key: SecretKey,
pub chain_code: ChainCode,
}
impl ExtendedPrivKey {
/// Generate an ExtendedPrivKey from seed
pub fn with_seed(seed: &[u8]) -> Result<ExtendedPrivKey, Error> {
let signature = {
let signing_key = Key::new(hmac::HMAC_SHA512, b"Bitcoin seed");
let mut h = Context::with_key(&signing_key);
h.update(&seed);
h.sign()
};
let sig_bytes = signature.as_ref();
let (key, chain_code) = sig_bytes.split_at(sig_bytes.len() / 2);
let private_key = SecretKey::from_slice(key)?;
Ok(ExtendedPrivKey {
private_key,
chain_code: chain_code.to_vec(),
})
}
fn sign_hardended_key(&self, index: u32) -> ring::hmac::Tag {
let signing_key = Key::new(hmac::HMAC_SHA512, &self.chain_code);
let mut h = Context::with_key(&signing_key);
h.update(&[0x00]);
h.update(&self.private_key[..]);
h.update(&index.to_be_bytes());
h.sign()
}
fn sign_normal_key(&self, index: u32) -> ring::hmac::Tag {
let signing_key = Key::new(hmac::HMAC_SHA512, &self.chain_code);
let mut h = Context::with_key(&signing_key);
let public_key = PublicKey::from_secret_key(&SECP256K1_SIGN_ONLY, &self.private_key);
h.update(&public_key.serialize());
h.update(&index.to_be_bytes());
h.sign()
}
/// Derive a child key from ExtendedPrivKey.
pub fn derive_private_key(&self, key_index: KeyIndex) -> Result<ExtendedPrivKey, Error> {
if !key_index.is_valid() {
return Err(Error::InvalidTweak);
}
let signature = match key_index {
KeyIndex::Hardened(index) => self.sign_hardended_key(index),
KeyIndex::Normal(index) => self.sign_normal_key(index),
};
let sig_bytes = signature.as_ref();
let (key, chain_code) = sig_bytes.split_at(sig_bytes.len() / 2);
let mut private_key = SecretKey::from_slice(key)?;
private_key.add_assign(&self.private_key[..])?;
Ok(ExtendedPrivKey {
private_key,
chain_code: chain_code.to_vec(),
})
}
}

View File

@@ -1,123 +1,123 @@
//! Abstractions over the proving system and parameters for ease of use.
use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey};
use pairing::bls12_381::{Bls12, Fr};
use zcash_primitives::{
jubjub::{edwards, fs::Fs, Unknown},
primitives::{Diversifier, PaymentAddress, ProofGenerationKey},
redjubjub::{PublicKey, Signature},
transaction::components::Amount
};
use zcash_primitives::{
merkle_tree::CommitmentTreeWitness, prover::TxProver, sapling::Node,
transaction::components::GROTH_PROOF_SIZE, JUBJUB,
};
use zcash_proofs::sapling::SaplingProvingContext;
/// An implementation of [`TxProver`] using Sapling Spend and Output parameters provided
/// in-memory.
pub struct InMemTxProver {
spend_params: Parameters<Bls12>,
spend_vk: PreparedVerifyingKey<Bls12>,
output_params: Parameters<Bls12>,
}
impl InMemTxProver {
pub fn new(spend_params: &[u8], output_params: &[u8]) -> Self {
// Deserialize params
let spend_params = Parameters::<Bls12>::read(spend_params, false)
.expect("couldn't deserialize Sapling spend parameters file");
let output_params = Parameters::<Bls12>::read(output_params, false)
.expect("couldn't deserialize Sapling spend parameters file");
// Prepare verifying keys
let spend_vk = prepare_verifying_key(&spend_params.vk);
InMemTxProver {
spend_params,
spend_vk,
output_params,
}
}
}
impl TxProver for InMemTxProver {
type SaplingProvingContext = SaplingProvingContext;
fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext {
SaplingProvingContext::new()
}
fn spend_proof(
&self,
ctx: &mut Self::SaplingProvingContext,
proof_generation_key: ProofGenerationKey<Bls12>,
diversifier: Diversifier,
rcm: Fs,
ar: Fs,
value: u64,
anchor: Fr,
witness: CommitmentTreeWitness<Node>,
) -> Result<
(
[u8; GROTH_PROOF_SIZE],
edwards::Point<Bls12, Unknown>,
PublicKey<Bls12>,
),
(),
> {
let (proof, cv, rk) = ctx.spend_proof(
proof_generation_key,
diversifier,
rcm,
ar,
value,
anchor,
witness,
&self.spend_params,
&self.spend_vk,
&JUBJUB,
)?;
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
Ok((zkproof, cv, rk))
}
fn output_proof(
&self,
ctx: &mut Self::SaplingProvingContext,
esk: Fs,
payment_address: PaymentAddress<Bls12>,
rcm: Fs,
value: u64,
) -> ([u8; GROTH_PROOF_SIZE], edwards::Point<Bls12, Unknown>) {
let (proof, cv) = ctx.output_proof(
esk,
payment_address,
rcm,
value,
&self.output_params,
&JUBJUB,
);
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
(zkproof, cv)
}
fn binding_sig(
&self,
ctx: &mut Self::SaplingProvingContext,
value_balance: Amount,
sighash: &[u8; 32],
) -> Result<Signature, ()> {
ctx.binding_sig(value_balance, sighash, &JUBJUB)
}
}
//! Abstractions over the proving system and parameters for ease of use.
use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey};
use pairing::bls12_381::{Bls12, Fr};
use zcash_primitives::{
jubjub::{edwards, fs::Fs, Unknown},
primitives::{Diversifier, PaymentAddress, ProofGenerationKey},
redjubjub::{PublicKey, Signature},
transaction::components::Amount
};
use zcash_primitives::{
merkle_tree::CommitmentTreeWitness, prover::TxProver, sapling::Node,
transaction::components::GROTH_PROOF_SIZE, JUBJUB,
};
use zcash_proofs::sapling::SaplingProvingContext;
/// An implementation of [`TxProver`] using Sapling Spend and Output parameters provided
/// in-memory.
pub struct InMemTxProver {
spend_params: Parameters<Bls12>,
spend_vk: PreparedVerifyingKey<Bls12>,
output_params: Parameters<Bls12>,
}
impl InMemTxProver {
pub fn new(spend_params: &[u8], output_params: &[u8]) -> Self {
// Deserialize params
let spend_params = Parameters::<Bls12>::read(spend_params, false)
.expect("couldn't deserialize Sapling spend parameters file");
let output_params = Parameters::<Bls12>::read(output_params, false)
.expect("couldn't deserialize Sapling spend parameters file");
// Prepare verifying keys
let spend_vk = prepare_verifying_key(&spend_params.vk);
InMemTxProver {
spend_params,
spend_vk,
output_params,
}
}
}
impl TxProver for InMemTxProver {
type SaplingProvingContext = SaplingProvingContext;
fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext {
SaplingProvingContext::new()
}
fn spend_proof(
&self,
ctx: &mut Self::SaplingProvingContext,
proof_generation_key: ProofGenerationKey<Bls12>,
diversifier: Diversifier,
rcm: Fs,
ar: Fs,
value: u64,
anchor: Fr,
witness: CommitmentTreeWitness<Node>,
) -> Result<
(
[u8; GROTH_PROOF_SIZE],
edwards::Point<Bls12, Unknown>,
PublicKey<Bls12>,
),
(),
> {
let (proof, cv, rk) = ctx.spend_proof(
proof_generation_key,
diversifier,
rcm,
ar,
value,
anchor,
witness,
&self.spend_params,
&self.spend_vk,
&JUBJUB,
)?;
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
Ok((zkproof, cv, rk))
}
fn output_proof(
&self,
ctx: &mut Self::SaplingProvingContext,
esk: Fs,
payment_address: PaymentAddress<Bls12>,
rcm: Fs,
value: u64,
) -> ([u8; GROTH_PROOF_SIZE], edwards::Point<Bls12, Unknown>) {
let (proof, cv) = ctx.output_proof(
esk,
payment_address,
rcm,
value,
&self.output_params,
&JUBJUB,
);
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
(zkproof, cv)
}
fn binding_sig(
&self,
ctx: &mut Self::SaplingProvingContext,
value_balance: Amount,
sighash: &[u8; 32],
) -> Result<Signature, ()> {
ctx.binding_sig(value_balance, sighash, &JUBJUB)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,21 @@
use std::io::{self, Read, Write};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
pub fn read_string<R: Read>(mut reader: R) -> io::Result<String> {
// Strings are written as <littleendian> len + bytes
let str_len = reader.read_u64::<LittleEndian>()?;
let mut str_bytes = vec![0; str_len as usize];
reader.read_exact(&mut str_bytes)?;
let str = String::from_utf8(str_bytes).map_err(|e| {
io::Error::new(io::ErrorKind::InvalidData, e.to_string())
})?;
Ok(str)
}
pub fn write_string<W: Write>(mut writer: W, s: &String) -> io::Result<()> {
// Strings are written as len + utf8
writer.write_u64::<LittleEndian>(s.as_bytes().len() as u64)?;
writer.write_all(s.as_bytes())
use std::io::{self, Read, Write};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
pub fn read_string<R: Read>(mut reader: R) -> io::Result<String> {
// Strings are written as <littleendian> len + bytes
let str_len = reader.read_u64::<LittleEndian>()?;
let mut str_bytes = vec![0; str_len as usize];
reader.read_exact(&mut str_bytes)?;
let str = String::from_utf8(str_bytes).map_err(|e| {
io::Error::new(io::ErrorKind::InvalidData, e.to_string())
})?;
Ok(str)
}
pub fn write_string<W: Write>(mut writer: W, s: &String) -> io::Result<()> {
// Strings are written as len + utf8
writer.write_u64::<LittleEndian>(s.as_bytes().len() as u64)?;
writer.write_all(s.as_bytes())
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,111 +1,111 @@
#!/bin/bash
# This script depends on a docker image already being built
# To build it,
# cd docker
# docker build --tag rustbuild:latest .
POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-v|--version)
APP_VERSION="$2"
shift # past argument
shift # past value
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
if [ -z $APP_VERSION ]; then echo "APP_VERSION is not set"; exit 1; fi
# Write the version file
echo "pub const VERSION:&str = \"$APP_VERSION\";" > /cli/src/version.rs
# First, do the tests
cd lib && cargo test --release
retVal=$?
if [ $retVal -ne 0 ]; then
echo "Error"
exit $retVal
fi
cd ..
# Compile for mac directly
cargo build --release
#macOS
rm -rf 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/
# 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"
# Now sign and zip the binaries
# 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
cd target
cd macOS-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt
cd ..
zip -r macOS-silentdragonxlite-cli-v$APP_VERSION.zip macOS-silentdragonxlite-cli-v$APP_VERSION
cd ..
#Linux
rm -rf 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/
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 linux-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt
cd ..
zip -r linux-silentdragonxlite-cli-v$APP_VERSION.zip linux-silentdragonxlite-cli-v$APP_VERSION
cd ..
#Windows
rm -rf 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/
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 Windows-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli.exe > sha256sum.txt
cd ..
zip -r Windows-silentdragonxlite-cli-v$APP_VERSION.zip Windows-silentdragonxlite-cli-v$APP_VERSION
cd ..
#Armv7
rm -rf 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/
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 Armv7-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt
cd ..
zip -r Armv7-silentdragonxlite-cli-v$APP_VERSION.zip Armv7-silentdragonxlite-cli-v$APP_VERSION
cd ..
#AARCH64
rm -rf 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/
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 aarch64-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt
cd ..
zip -r aarch64-silentdragonxlite-cli-v$APP_VERSION.zip aarch64-silentdragonxlite-cli-v$APP_VERSION
cd ..
#!/bin/bash
# This script depends on a docker image already being built
# To build it,
# cd docker
# docker build --tag rustbuild:latest .
POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-v|--version)
APP_VERSION="$2"
shift # past argument
shift # past value
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
if [ -z $APP_VERSION ]; then echo "APP_VERSION is not set"; exit 1; fi
# Write the version file
echo "pub const VERSION:&str = \"$APP_VERSION\";" > /cli/src/version.rs
# First, do the tests
cd lib && cargo test --release
retVal=$?
if [ $retVal -ne 0 ]; then
echo "Error"
exit $retVal
fi
cd ..
# Compile for mac directly
cargo build --release
#macOS
rm -rf 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/
# 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"
# Now sign and zip the binaries
# 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
cd target
cd macOS-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt
cd ..
zip -r macOS-silentdragonxlite-cli-v$APP_VERSION.zip macOS-silentdragonxlite-cli-v$APP_VERSION
cd ..
#Linux
rm -rf 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/
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 linux-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt
cd ..
zip -r linux-silentdragonxlite-cli-v$APP_VERSION.zip linux-silentdragonxlite-cli-v$APP_VERSION
cd ..
#Windows
rm -rf 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/
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 Windows-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli.exe > sha256sum.txt
cd ..
zip -r Windows-silentdragonxlite-cli-v$APP_VERSION.zip Windows-silentdragonxlite-cli-v$APP_VERSION
cd ..
#Armv7
rm -rf 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/
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 Armv7-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt
cd ..
zip -r Armv7-silentdragonxlite-cli-v$APP_VERSION.zip Armv7-silentdragonxlite-cli-v$APP_VERSION
cd ..
#AARCH64
rm -rf 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/
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 aarch64-silentdragonxlite-cli-v$APP_VERSION
gsha256sum silentdragonxlite-cli > sha256sum.txt
cd ..
zip -r aarch64-silentdragonxlite-cli-v$APP_VERSION.zip aarch64-silentdragonxlite-cli-v$APP_VERSION
cd ..

View File

@@ -1,50 +1,50 @@
#!/usr/bin/env bash
# Copyright 2021-2022 The Hush Developers
# Distributed under the GPLv3 software license, see the accompanying
# file LICENSE or https://www.gnu.org/licenses/gpl-3.0.en.html
# Purpose: Script to build Hush silentdragonxlite on x86 64-bit arch
## Usage: ./util/build.sh
# Check if rustc is installed on system and exits if it is not
if ! [ -x "$(command -v rustc)" ]; then
echo 'Error: rustc is not installed. Install it and try again.' >&2
exit 1
fi
# Check if cargo is installed on system and exits if it is not
if ! [ -x "$(command -v cargo)" ]; then
echo 'Error: cargo is not installed. Install it and try again.' >&2
exit 1
fi
# Check if rustfmt is installed on system and exits if it is not
if ! [ -x "$(command -v rustfmt)" ]; then
echo 'Error: rustfmt is not installed. Install it and try again.' >&2
exit 1
fi
echo ""
echo "Welcome to the Hush magic folks..."
echo ""
echo " #### ##### # #### # # ##### # # # # ##### ##### # # # ###### "
echo "# # # # # # # # # # # # # # # # # # ## ## # "
echo " #### # # # ##### # # # ##### # # # # # # # # # ## # ##### "
echo " # # # # # # # # # # # # # # # # # # # # "
echo "# # # # # # # # # # # # # # # # # # # # # # "
echo " #### ##### ###### #### ###### # ##### #### # ###### ##### # # # # ###### "
# now to compiling...
echo ""
echo "You have the requirements installed, so let's build!"
cargo build --release
# check if compile was success
if [ $? -ne 0 ]; then
echo ""
echo 'Error: Something went wrong and it did not build successfully... Please reach out if you need support.' >&2
exit 1
fi
echo ""
echo "Hush silentdragonxlite-cli is now compiled for you. Enjoy and reach out if you need support."
echo "For options, run ./silentdragonxlite --help"
#!/usr/bin/env bash
# Copyright 2021-2022 The Hush Developers
# Distributed under the GPLv3 software license, see the accompanying
# file LICENSE or https://www.gnu.org/licenses/gpl-3.0.en.html
# Purpose: Script to build Hush silentdragonxlite on x86 64-bit arch
## Usage: ./util/build.sh
# Check if rustc is installed on system and exits if it is not
if ! [ -x "$(command -v rustc)" ]; then
echo 'Error: rustc is not installed. Install it and try again.' >&2
exit 1
fi
# Check if cargo is installed on system and exits if it is not
if ! [ -x "$(command -v cargo)" ]; then
echo 'Error: cargo is not installed. Install it and try again.' >&2
exit 1
fi
# Check if rustfmt is installed on system and exits if it is not
if ! [ -x "$(command -v rustfmt)" ]; then
echo 'Error: rustfmt is not installed. Install it and try again.' >&2
exit 1
fi
echo ""
echo "Welcome to the Hush magic folks..."
echo ""
echo " #### ##### # #### # # ##### # # # # ##### ##### # # # ###### "
echo "# # # # # # # # # # # # # # # # # # ## ## # "
echo " #### # # # ##### # # # ##### # # # # # # # # # ## # ##### "
echo " # # # # # # # # # # # # # # # # # # # # "
echo "# # # # # # # # # # # # # # # # # # # # # # "
echo " #### ##### ###### #### ###### # ##### #### # ###### ##### # # # # ###### "
# now to compiling...
echo ""
echo "You have the requirements installed, so let's build!"
cargo build --release
# check if compile was success
if [ $? -ne 0 ]; then
echo ""
echo 'Error: Something went wrong and it did not build successfully... Please reach out if you need support.' >&2
exit 1
fi
echo ""
echo "Hush silentdragonxlite-cli is now compiled for you. Enjoy and reach out if you need support."
echo "For options, run ./silentdragonxlite --help"