Merge pull request #7 from DenioD/master
decryption and many other updates
This commit is contained in:
88
.github/workflows/rust.yml
vendored
Normal file
88
.github/workflows/rust.yml
vendored
Normal file
@@ -0,0 +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
|
||||||
|
|
||||||
104
.github/workflows/rust_BACKUP_5752.yml
vendored
Normal file
104
.github/workflows/rust_BACKUP_5752.yml
vendored
Normal file
@@ -0,0 +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
|
||||||
|
|
||||||
80
.github/workflows/rust_BASE_5752.yml
vendored
Normal file
80
.github/workflows/rust_BASE_5752.yml
vendored
Normal file
@@ -0,0 +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
|
||||||
|
|
||||||
93
.github/workflows/rust_LOCAL_5752.yml
vendored
Normal file
93
.github/workflows/rust_LOCAL_5752.yml
vendored
Normal file
@@ -0,0 +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
|
||||||
|
|
||||||
88
.github/workflows/rust_REMOTE_5752.yml
vendored
Normal file
88
.github/workflows/rust_REMOTE_5752.yml
vendored
Normal file
@@ -0,0 +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
|
||||||
|
|
||||||
23
Cargo.toml
23
Cargo.toml
@@ -1,21 +1,8 @@
|
|||||||
[package]
|
[workspace]
|
||||||
name = "silentdragonlite-cli"
|
members = [
|
||||||
version = "1.1.0"
|
"lib",
|
||||||
edition = "2018"
|
"cli",
|
||||||
|
]
|
||||||
[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.1"
|
|
||||||
byteorder = "1"
|
|
||||||
tiny-bip39 = "0.6.2"
|
|
||||||
|
|
||||||
silentdragonlitelib = { path = "./lib/" }
|
|
||||||
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = false
|
debug = false
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
## Zecwallet-cli BIP39 derivation bug
|
## silentdragonlite-cli BIP39 derivation bug
|
||||||
|
|
||||||
In v1.0 of zecwallet-cli, there was a bug that incorrectly derived HD wallet keys after the first key. That is, the first key, address was correct, but subsequent ones were not.
|
In v1.0 of silentdragonlite-cli, there was a bug that incorrectly derived HD wallet keys after the first key. That is, the first key, address was correct, but subsequent ones were not.
|
||||||
|
|
||||||
The issue was that the 32-byte seed was directly being used to derive then subsequent addresses instead of the 64-byte pkdf2(seed). The issue affected both t and z addresses.
|
The issue was that the 32-byte seed was directly being used to derive then subsequent addresses instead of the 64-byte pkdf2(seed). The issue affected both t and z addresses.
|
||||||
|
|
||||||
@@ -8,6 +8,6 @@ Note that no funds are at risk. The issue is that, if in the future, you import
|
|||||||
|
|
||||||
## Fix
|
## Fix
|
||||||
If you start a wallet that has this bug, you'll be notified.
|
If you start a wallet that has this bug, you'll be notified.
|
||||||
The bug can be automatically fixed by the wallet by running the `fixbip39bug` command. Just start `zecwallet-cli` and type `fixbip39bug`.
|
The bug can be automatically fixed by the wallet by running the `fixbip39bug` command. Just start `silentdragonlite-cli` and type `fixbip39bug`.
|
||||||
|
|
||||||
If you have any funds in the incorrect addresses, they'll be sent to yourself, and the correct addresses re-derived.
|
If you have any funds in the incorrect addresses, they'll be sent to yourself, and the correct addresses re-derived.
|
||||||
18
cli/Cargo.toml
Normal file
18
cli/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "silentdragonlite-cli"
|
||||||
|
version = "1.1.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.1"
|
||||||
|
byteorder = "1"
|
||||||
|
tiny-bip39 = "0.6.2"
|
||||||
|
|
||||||
|
silentdragonlitelib = { path = "../lib/" }
|
||||||
|
|
||||||
@@ -61,6 +61,11 @@ pub fn main() {
|
|||||||
.value_name("seed_phrase")
|
.value_name("seed_phrase")
|
||||||
.help("Create a new wallet with the given 24-word seed phrase. Will fail if wallet already exists")
|
.help("Create a new wallet with the given 24-word seed phrase. Will fail if wallet already exists")
|
||||||
.takes_value(true))
|
.takes_value(true))
|
||||||
|
.arg(Arg::with_name("birthday")
|
||||||
|
.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")
|
.arg(Arg::with_name("server")
|
||||||
.long("server")
|
.long("server")
|
||||||
.value_name("server")
|
.value_name("server")
|
||||||
@@ -113,7 +118,24 @@ pub fn main() {
|
|||||||
let params = matches.values_of("PARAMS").map(|v| v.collect()).or(Some(vec![])).unwrap();
|
let params = matches.values_of("PARAMS").map(|v| v.collect()).or(Some(vec![])).unwrap();
|
||||||
|
|
||||||
let maybe_server = matches.value_of("server").map(|s| s.to_string());
|
let maybe_server = matches.value_of("server").map(|s| s.to_string());
|
||||||
|
|
||||||
let seed = matches.value_of("seed").map(|s| s.to_string());
|
let seed = matches.value_of("seed").map(|s| s.to_string());
|
||||||
|
let maybe_birthday = matches.value_of("birthday");
|
||||||
|
|
||||||
|
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);
|
let server = LightClientConfig::get_server_or_default(maybe_server);
|
||||||
|
|
||||||
@@ -125,7 +147,7 @@ pub fn main() {
|
|||||||
|
|
||||||
let dangerous = matches.is_present("dangerous");
|
let dangerous = matches.is_present("dangerous");
|
||||||
let nosync = matches.is_present("nosync");
|
let nosync = matches.is_present("nosync");
|
||||||
let (command_tx, resp_rx) = match startup(server, dangerous, seed, !nosync, command.is_none()) {
|
let (command_tx, resp_rx) = match startup(server, dangerous, seed, birthday, !nosync, command.is_none()) {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error during startup: {}", e);
|
eprintln!("Error during startup: {}", e);
|
||||||
@@ -163,7 +185,7 @@ pub fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn startup(server: http::Uri, dangerous: bool, seed: Option<String>, first_sync: bool, print_updates: bool)
|
fn startup(server: http::Uri, dangerous: bool, seed: Option<String>, birthday: u64, first_sync: bool, print_updates: bool)
|
||||||
-> io::Result<(Sender<(String, Vec<String>)>, Receiver<String>)> {
|
-> io::Result<(Sender<(String, Vec<String>)>, Receiver<String>)> {
|
||||||
// Try to get the configuration
|
// Try to get the configuration
|
||||||
let (config, latest_block_height) = LightClientConfig::create(server.clone(), dangerous)?;
|
let (config, latest_block_height) = LightClientConfig::create(server.clone(), dangerous)?;
|
||||||
@@ -175,7 +197,7 @@ fn startup(server: http::Uri, dangerous: bool, seed: Option<String>, first_sync:
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let lightclient = match seed {
|
let lightclient = match seed {
|
||||||
Some(phrase) => Arc::new(LightClient::new_from_phrase(phrase, &config, latest_block_height)?),
|
Some(phrase) => Arc::new(LightClient::new_from_phrase(phrase, &config, birthday)?),
|
||||||
None => {
|
None => {
|
||||||
if config.wallet_exists() {
|
if config.wallet_exists() {
|
||||||
Arc::new(LightClient::read_from_disk(&config)?)
|
Arc::new(LightClient::read_from_disk(&config)?)
|
||||||
@@ -195,9 +217,6 @@ fn startup(server: http::Uri, dangerous: bool, seed: Option<String>, first_sync:
|
|||||||
println!("Lightclient connecting to {}", config.server);
|
println!("Lightclient connecting to {}", config.server);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the command loop
|
|
||||||
let (command_tx, resp_rx) = command_loop(lightclient.clone());
|
|
||||||
|
|
||||||
// At startup, run a sync.
|
// At startup, run a sync.
|
||||||
if first_sync {
|
if first_sync {
|
||||||
let update = lightclient.do_sync(true);
|
let update = lightclient.do_sync(true);
|
||||||
@@ -206,6 +225,9 @@ fn startup(server: http::Uri, dangerous: bool, seed: Option<String>, first_sync:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start the command loop
|
||||||
|
let (command_tx, resp_rx) = command_loop(lightclient.clone());
|
||||||
|
|
||||||
Ok((command_tx, resp_rx))
|
Ok((command_tx, resp_rx))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ RUN cd /opt && wget https://download.libsodium.org/libsodium/releases/libsodium-
|
|||||||
tar xvf libsodium-1.0.17-mingw.tar.gz
|
tar xvf libsodium-1.0.17-mingw.tar.gz
|
||||||
|
|
||||||
# Cargo fetch the dependencies so we don't download them over and over again
|
# Cargo fetch the dependencies so we don't download them over and over again
|
||||||
RUN cd /tmp && git clone https://github.com/adityapk00/zecwallet-light-cli.git && \
|
RUN cd /tmp && git clone https://github.com/adityapk00/silentdragonlite-light-cli.git && \
|
||||||
cd zecwallet-light-cli && \
|
cd silentdragonlite-light-cli && \
|
||||||
cargo fetch && \
|
cargo fetch && \
|
||||||
cd /tmp && rm -rf zecwallet-light-cli
|
cd /tmp && rm -rf silentdragonlite-light-cli
|
||||||
|
|||||||
@@ -38,34 +38,34 @@ sodiumoxide = "0.2.5"
|
|||||||
|
|
||||||
[dependencies.bellman]
|
[dependencies.bellman]
|
||||||
git = "https://github.com/DenioD/librustzcash.git"
|
git = "https://github.com/DenioD/librustzcash.git"
|
||||||
rev= "44a1c3981df37b73d87f0e625ca3557d8534e6f3"
|
rev= "caaee693c47c2ee9ecd1e1546b8fe3c714f342bc"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["groth16"]
|
features = ["groth16"]
|
||||||
|
|
||||||
[dependencies.pairing]
|
[dependencies.pairing]
|
||||||
git = "https://github.com/DenioD/librustzcash.git"
|
git = "https://github.com/DenioD/librustzcash.git"
|
||||||
rev= "44a1c3981df37b73d87f0e625ca3557d8534e6f3"
|
rev= "caaee693c47c2ee9ecd1e1546b8fe3c714f342bc"
|
||||||
|
|
||||||
[dependencies.zcash_client_backend]
|
[dependencies.zcash_client_backend]
|
||||||
git = "https://github.com/DenioD/librustzcash.git"
|
git = "https://github.com/DenioD/librustzcash.git"
|
||||||
rev= "44a1c3981df37b73d87f0e625ca3557d8534e6f3"
|
rev= "caaee693c47c2ee9ecd1e1546b8fe3c714f342bc"
|
||||||
|
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dependencies.zcash_primitives]
|
[dependencies.zcash_primitives]
|
||||||
git = "https://github.com/DenioD/librustzcash.git"
|
git = "https://github.com/DenioD/librustzcash.git"
|
||||||
rev= "44a1c3981df37b73d87f0e625ca3557d8534e6f3"
|
rev= "caaee693c47c2ee9ecd1e1546b8fe3c714f342bc"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["transparent-inputs"]
|
features = ["transparent-inputs"]
|
||||||
|
|
||||||
[dependencies.zcash_proofs]
|
[dependencies.zcash_proofs]
|
||||||
git = "https://github.com/DenioD/librustzcash.git"
|
git = "https://github.com/DenioD/librustzcash.git"
|
||||||
rev= "44a1c3981df37b73d87f0e625ca3557d8534e6f3"
|
rev= "caaee693c47c2ee9ecd1e1546b8fe3c714f342bc"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dependencies.ff]
|
[dependencies.ff]
|
||||||
git = "https://github.com/DenioD/librustzcash.git"
|
git = "https://github.com/DenioD/librustzcash.git"
|
||||||
rev= "44a1c3981df37b73d87f0e625ca3557d8534e6f3"
|
rev= "caaee693c47c2ee9ecd1e1546b8fe3c714f342bc"
|
||||||
features = ["ff_derive"]
|
features = ["ff_derive"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
@@ -73,6 +73,3 @@ tower-grpc-build = { git = "https://github.com/tower-rs/tower-grpc", features =
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempdir = "0.3.7"
|
tempdir = "0.3.7"
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
debug = true
|
|
||||||
@@ -356,7 +356,11 @@ impl Command for LockCommand {
|
|||||||
|
|
||||||
fn exec(&self, args: &[&str], lightclient: &LightClient) -> String {
|
fn exec(&self, args: &[&str], lightclient: &LightClient) -> String {
|
||||||
if args.len() != 0 {
|
if args.len() != 0 {
|
||||||
return self.help();
|
let mut h = vec![];
|
||||||
|
h.push("Extra arguments to lock. Did you mean 'encrypt'?");
|
||||||
|
h.push("");
|
||||||
|
|
||||||
|
return format!("{}\n{}", h.join("\n"), self.help());
|
||||||
}
|
}
|
||||||
|
|
||||||
match lightclient.wallet.write().unwrap().lock() {
|
match lightclient.wallet.write().unwrap().lock() {
|
||||||
@@ -378,7 +382,7 @@ impl Command for SendCommand {
|
|||||||
h.push("Usage:");
|
h.push("Usage:");
|
||||||
h.push("send <address> <amount in puposhis> \"optional_memo\"");
|
h.push("send <address> <amount in puposhis> \"optional_memo\"");
|
||||||
h.push("OR");
|
h.push("OR");
|
||||||
h.push("send '[{'address': <address>, 'amount': <amount in zatoshis>, 'memo': <optional memo>}, ...]'");
|
h.push("send '[{'address': <address>, 'amount': <amount in puposhis>, 'memo': <optional memo>}, ...]'");
|
||||||
h.push("");
|
h.push("");
|
||||||
h.push("Example:");
|
h.push("Example:");
|
||||||
h.push("send ztestsapling1x65nq4dgp0qfywgxcwk9n0fvm4fysmapgr2q00p85ju252h6l7mmxu2jg9cqqhtvzd69jwhgv8d 200000 \"Hello from the command line\"");
|
h.push("send ztestsapling1x65nq4dgp0qfywgxcwk9n0fvm4fysmapgr2q00p85ju252h6l7mmxu2jg9cqqhtvzd69jwhgv8d 200000 \"Hello from the command line\"");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::lightwallet::LightWallet;
|
|||||||
use log::{info, warn, error};
|
use log::{info, warn, error};
|
||||||
use rand::{rngs::OsRng, seq::SliceRandom};
|
use rand::{rngs::OsRng, seq::SliceRandom};
|
||||||
|
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock, Mutex};
|
||||||
use std::sync::atomic::{AtomicU64, AtomicI32, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicU64, AtomicI32, AtomicUsize, Ordering};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@@ -25,6 +25,8 @@ use crate::grpcconnector::{self, *};
|
|||||||
use crate::SaplingParams;
|
use crate::SaplingParams;
|
||||||
use crate::ANCHOR_OFFSET;
|
use crate::ANCHOR_OFFSET;
|
||||||
|
|
||||||
|
mod checkpoints;
|
||||||
|
|
||||||
pub const DEFAULT_SERVER: &str = "https://";
|
pub const DEFAULT_SERVER: &str = "https://";
|
||||||
pub const WALLET_NAME: &str = "silentdragonlite-cli-wallet.dat";
|
pub const WALLET_NAME: &str = "silentdragonlite-cli-wallet.dat";
|
||||||
pub const LOGFILE_NAME: &str = "silentdragonlite-cli-wallet.debug.log";
|
pub const LOGFILE_NAME: &str = "silentdragonlite-cli-wallet.debug.log";
|
||||||
@@ -117,18 +119,8 @@ impl LightClientConfig {
|
|||||||
log_path.into_boxed_path()
|
log_path.into_boxed_path()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_initial_state(&self) -> Option<(u64, &str, &str)> {
|
pub fn get_initial_state(&self, height: u64) -> Option<(u64, &str, &str)> {
|
||||||
match &self.chain_name[..] {
|
checkpoints::get_closest_checkpoint(&self.chain_name, height)
|
||||||
"test" => Some((105942,
|
|
||||||
"00000001c0199f329ee03379bf1387856dbab23765da508bf9b9d8d544f212c0",
|
|
||||||
""
|
|
||||||
)),
|
|
||||||
"main" => Some((105944,
|
|
||||||
"0000000313b0ec7c5a1e9b997ce44a7763b56c5505526c36634a004ed52d7787",
|
|
||||||
""
|
|
||||||
)),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_server_or_default(server: Option<String>) -> http::Uri {
|
pub fn get_server_or_default(server: Option<String>) -> http::Uri {
|
||||||
@@ -209,14 +201,16 @@ pub struct LightClient {
|
|||||||
// zcash-params
|
// zcash-params
|
||||||
pub sapling_output : Vec<u8>,
|
pub sapling_output : Vec<u8>,
|
||||||
pub sapling_spend : Vec<u8>,
|
pub sapling_spend : Vec<u8>,
|
||||||
|
|
||||||
|
sync_lock : Mutex<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LightClient {
|
impl LightClient {
|
||||||
|
|
||||||
pub fn set_wallet_initial_state(&self) {
|
pub fn set_wallet_initial_state(&self, height: u64) {
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
let state = self.config.get_initial_state();
|
let state = self.config.get_initial_state(height);
|
||||||
|
|
||||||
match state {
|
match state {
|
||||||
Some((height, hash, tree)) => self.wallet.read().unwrap().set_initial_block(height.try_into().unwrap(), hash, tree),
|
Some((height, hash, tree)) => self.wallet.read().unwrap().set_initial_block(height.try_into().unwrap(), hash, tree),
|
||||||
@@ -239,10 +233,11 @@ impl LightClient {
|
|||||||
wallet : Arc::new(RwLock::new(LightWallet::new(Some(seed_phrase), &config, 0)?)),
|
wallet : Arc::new(RwLock::new(LightWallet::new(Some(seed_phrase), &config, 0)?)),
|
||||||
config : config.clone(),
|
config : config.clone(),
|
||||||
sapling_output : vec![],
|
sapling_output : vec![],
|
||||||
sapling_spend : vec![]
|
sapling_spend : vec![],
|
||||||
|
sync_lock : Mutex::new(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
l.set_wallet_initial_state();
|
l.set_wallet_initial_state(0);
|
||||||
l.read_sapling_params();
|
l.read_sapling_params();
|
||||||
|
|
||||||
info!("Created new wallet!");
|
info!("Created new wallet!");
|
||||||
@@ -263,10 +258,11 @@ impl LightClient {
|
|||||||
wallet : Arc::new(RwLock::new(LightWallet::new(None, config, latest_block)?)),
|
wallet : Arc::new(RwLock::new(LightWallet::new(None, config, latest_block)?)),
|
||||||
config : config.clone(),
|
config : config.clone(),
|
||||||
sapling_output : vec![],
|
sapling_output : vec![],
|
||||||
sapling_spend : vec![]
|
sapling_spend : vec![],
|
||||||
|
sync_lock : Mutex::new(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
l.set_wallet_initial_state();
|
l.set_wallet_initial_state(latest_block);
|
||||||
l.read_sapling_params();
|
l.read_sapling_params();
|
||||||
|
|
||||||
info!("Created new wallet with a new seed!");
|
info!("Created new wallet with a new seed!");
|
||||||
@@ -275,20 +271,22 @@ impl LightClient {
|
|||||||
Ok(l)
|
Ok(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_phrase(seed_phrase: String, config: &LightClientConfig, latest_block: u64) -> io::Result<Self> {
|
pub fn new_from_phrase(seed_phrase: String, config: &LightClientConfig, birthday: u64) -> io::Result<Self> {
|
||||||
if config.wallet_exists() {
|
if config.wallet_exists() {
|
||||||
return Err(Error::new(ErrorKind::AlreadyExists,
|
return Err(Error::new(ErrorKind::AlreadyExists,
|
||||||
"Cannot create a new wallet from seed, because a wallet already exists"));
|
"Cannot create a new wallet from seed, because a wallet already exists"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut l = LightClient {
|
let mut l = LightClient {
|
||||||
wallet : Arc::new(RwLock::new(LightWallet::new(Some(seed_phrase), config, latest_block)?)),
|
wallet : Arc::new(RwLock::new(LightWallet::new(Some(seed_phrase), config, birthday)?)),
|
||||||
config : config.clone(),
|
config : config.clone(),
|
||||||
sapling_output : vec![],
|
sapling_output : vec![],
|
||||||
sapling_spend : vec![]
|
sapling_spend : vec![],
|
||||||
|
sync_lock : Mutex::new(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
l.set_wallet_initial_state();
|
println!("Setting birthday to {}", birthday);
|
||||||
|
l.set_wallet_initial_state(birthday);
|
||||||
l.read_sapling_params();
|
l.read_sapling_params();
|
||||||
|
|
||||||
info!("Created new wallet!");
|
info!("Created new wallet!");
|
||||||
@@ -310,7 +308,8 @@ impl LightClient {
|
|||||||
wallet : Arc::new(RwLock::new(wallet)),
|
wallet : Arc::new(RwLock::new(wallet)),
|
||||||
config : config.clone(),
|
config : config.clone(),
|
||||||
sapling_output : vec![],
|
sapling_output : vec![],
|
||||||
sapling_spend : vec![]
|
sapling_spend : vec![],
|
||||||
|
sync_lock : Mutex::new(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
lc.read_sapling_params();
|
lc.read_sapling_params();
|
||||||
@@ -319,7 +318,7 @@ impl LightClient {
|
|||||||
info!("Created LightClient to {}", &config.server);
|
info!("Created LightClient to {}", &config.server);
|
||||||
|
|
||||||
if crate::lightwallet::bugs::BugBip39Derivation::has_bug(&lc) {
|
if crate::lightwallet::bugs::BugBip39Derivation::has_bug(&lc) {
|
||||||
let m = format!("WARNING!!!\nYour wallet has a bip39derivation bug that's showing incorrect addresses.\nPlease run 'fixbip39bug' to automatically fix the address derivation in your wallet!\nPlease see: https://github.com/adityapk00/zecwallet-light-cli/blob/master/bip39bug.md");
|
let m = format!("WARNING!!!\nYour wallet has a bip39derivation bug that's showing incorrect addresses.\nPlease run 'fixbip39bug' to automatically fix the address derivation in your wallet!\nPlease see: https://github.com/adityapk00/silentdragonlite-light-cli/blob/master/bip39bug.md");
|
||||||
info!("{}", m);
|
info!("{}", m);
|
||||||
println!("{}", m);
|
println!("{}", m);
|
||||||
}
|
}
|
||||||
@@ -709,8 +708,8 @@ impl LightClient {
|
|||||||
let wallet = self.wallet.write().unwrap();
|
let wallet = self.wallet.write().unwrap();
|
||||||
|
|
||||||
let new_address = match addr_type {
|
let new_address = match addr_type {
|
||||||
"z" => wallet.add_zaddr(),
|
"zs" => wallet.add_zaddr(),
|
||||||
"t" => wallet.add_taddr(),
|
"R" => wallet.add_taddr(),
|
||||||
_ => {
|
_ => {
|
||||||
let e = format!("Unrecognized address type: {}", addr_type);
|
let e = format!("Unrecognized address type: {}", addr_type);
|
||||||
error!("{}", e);
|
error!("{}", e);
|
||||||
@@ -727,7 +726,7 @@ impl LightClient {
|
|||||||
self.wallet.read().unwrap().clear_blocks();
|
self.wallet.read().unwrap().clear_blocks();
|
||||||
|
|
||||||
// Then set the initial block
|
// Then set the initial block
|
||||||
self.set_wallet_initial_state();
|
self.set_wallet_initial_state(self.wallet.read().unwrap().get_birthday());
|
||||||
|
|
||||||
// Then, do a sync, which will force a full rescan from the initial state
|
// Then, do a sync, which will force a full rescan from the initial state
|
||||||
let response = self.do_sync(true);
|
let response = self.do_sync(true);
|
||||||
@@ -737,6 +736,10 @@ impl LightClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_sync(&self, print_updates: bool) -> String {
|
pub fn do_sync(&self, print_updates: bool) -> String {
|
||||||
|
// We can only do one sync at a time because we sync blocks in serial order
|
||||||
|
// If we allow multiple syncs, they'll all get jumbled up.
|
||||||
|
let _lock = self.sync_lock.lock().unwrap();
|
||||||
|
|
||||||
// Sync is 3 parts
|
// Sync is 3 parts
|
||||||
// 1. Get the latest block
|
// 1. Get the latest block
|
||||||
// 2. Get all the blocks that we don't have
|
// 2. Get all the blocks that we don't have
|
||||||
@@ -976,24 +979,24 @@ pub mod tests {
|
|||||||
let lc = super::LightClient::unconnected(TEST_SEED.to_string(), None).unwrap();
|
let lc = super::LightClient::unconnected(TEST_SEED.to_string(), None).unwrap();
|
||||||
|
|
||||||
assert!(!lc.do_export(None).is_err());
|
assert!(!lc.do_export(None).is_err());
|
||||||
assert!(!lc.do_new_address("z").is_err());
|
assert!(!lc.do_new_address("zs").is_err());
|
||||||
assert!(!lc.do_new_address("t").is_err());
|
assert!(!lc.do_new_address("R").is_err());
|
||||||
assert_eq!(lc.do_seed_phrase().unwrap()["seed"], TEST_SEED.to_string());
|
assert_eq!(lc.do_seed_phrase().unwrap()["seed"], TEST_SEED.to_string());
|
||||||
|
|
||||||
// Encrypt and Lock the wallet
|
// Encrypt and Lock the wallet
|
||||||
lc.wallet.write().unwrap().encrypt("password".to_string()).unwrap();
|
lc.wallet.write().unwrap().encrypt("password".to_string()).unwrap();
|
||||||
assert!(lc.do_export(None).is_err());
|
assert!(lc.do_export(None).is_err());
|
||||||
assert!(lc.do_seed_phrase().is_err());
|
assert!(lc.do_seed_phrase().is_err());
|
||||||
assert!(lc.do_new_address("t").is_err());
|
assert!(lc.do_new_address("R").is_err());
|
||||||
assert!(lc.do_new_address("z").is_err());
|
assert!(lc.do_new_address("zs").is_err());
|
||||||
assert!(lc.do_send(vec![("z", 0, None)]).is_err());
|
assert!(lc.do_send(vec![("zs", 0, None)]).is_err());
|
||||||
|
|
||||||
// Do a unlock, and make sure it all works now
|
// Do a unlock, and make sure it all works now
|
||||||
lc.wallet.write().unwrap().unlock("password".to_string()).unwrap();
|
lc.wallet.write().unwrap().unlock("password".to_string()).unwrap();
|
||||||
assert!(!lc.do_export(None).is_err());
|
assert!(!lc.do_export(None).is_err());
|
||||||
assert!(!lc.do_seed_phrase().is_err());
|
assert!(!lc.do_seed_phrase().is_err());
|
||||||
assert!(!lc.do_new_address("t").is_err());
|
assert!(!lc.do_new_address("R").is_err());
|
||||||
assert!(!lc.do_new_address("z").is_err());
|
assert!(!lc.do_new_address("zs").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1002,10 +1005,10 @@ pub mod tests {
|
|||||||
|
|
||||||
// Add new z and t addresses
|
// Add new z and t addresses
|
||||||
|
|
||||||
let taddr1 = lc.do_new_address("t").unwrap()[0].as_str().unwrap().to_string();
|
let taddr1 = lc.do_new_address("R").unwrap()[0].as_str().unwrap().to_string();
|
||||||
let taddr2 = lc.do_new_address("t").unwrap()[0].as_str().unwrap().to_string();
|
let taddr2 = lc.do_new_address("R").unwrap()[0].as_str().unwrap().to_string();
|
||||||
let zaddr1 = lc.do_new_address("z").unwrap()[0].as_str().unwrap().to_string();
|
let zaddr1 = lc.do_new_address("zs").unwrap()[0].as_str().unwrap().to_string();
|
||||||
let zaddr2 = lc.do_new_address("z").unwrap()[0].as_str().unwrap().to_string();
|
let zaddr2 = lc.do_new_address("zs").unwrap()[0].as_str().unwrap().to_string();
|
||||||
|
|
||||||
let addresses = lc.do_address();
|
let addresses = lc.do_address();
|
||||||
assert_eq!(addresses["z_addresses"].len(), 3);
|
assert_eq!(addresses["z_addresses"].len(), 3);
|
||||||
|
|||||||
90
lib/src/lightclient/checkpoints.rs
Normal file
90
lib/src/lightclient/checkpoints.rs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
pub fn get_closest_checkpoint(chain_name: &str, height: u64) -> Option<(u64, &'static str, &'static str)> {
|
||||||
|
match chain_name {
|
||||||
|
"test" => get_test_checkpoint(height),
|
||||||
|
"main" => get_main_checkpoint(height),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_test_checkpoint(height: u64) -> Option<(u64, &'static str, &'static str)> {
|
||||||
|
let checkpoints: Vec<(u64, &str, &str)> = vec![
|
||||||
|
(105942, "",
|
||||||
|
""
|
||||||
|
),
|
||||||
|
(105943, "",
|
||||||
|
""
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
find_checkpoint(height, checkpoints)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn get_main_checkpoint(height: u64) -> Option<(u64, &'static str, &'static str)> {
|
||||||
|
let checkpoints: Vec<(u64, &str, &str)> = vec![
|
||||||
|
(105942, "00000001c0199f329ee03379bf1387856dbab23765da508bf9b9d8d544f212c0",
|
||||||
|
""
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
find_checkpoint(height, checkpoints)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_checkpoint(height: u64, chkpts: Vec<(u64, &'static str, &'static str)>) -> Option<(u64, &'static str, &'static str)> {
|
||||||
|
// Find the closest checkpoint
|
||||||
|
let mut heights = chkpts.iter().map(|(h, _, _)| *h as u64).collect::<Vec<_>>();
|
||||||
|
heights.sort();
|
||||||
|
|
||||||
|
match get_first_lower_than(height, heights) {
|
||||||
|
Some(closest_height) => {
|
||||||
|
chkpts.iter().find(|(h, _, _)| *h == closest_height).map(|t| *t)
|
||||||
|
},
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_first_lower_than(height: u64, heights: Vec<u64>) -> Option<u64> {
|
||||||
|
// If it's before the first checkpoint, return None.
|
||||||
|
if heights.len() == 0 || height < heights[0] {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, h) in heights.iter().enumerate() {
|
||||||
|
if height < *h {
|
||||||
|
return Some(heights[i-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(*heights.last().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lower_than() {
|
||||||
|
assert_eq!(get_first_lower_than( 9, vec![10, 30, 40]), None);
|
||||||
|
assert_eq!(get_first_lower_than(10, vec![10, 30, 40]).unwrap(), 10);
|
||||||
|
assert_eq!(get_first_lower_than(11, vec![10, 30, 40]).unwrap(), 10);
|
||||||
|
assert_eq!(get_first_lower_than(29, vec![10, 30, 40]).unwrap(), 10);
|
||||||
|
assert_eq!(get_first_lower_than(30, vec![10, 30, 40]).unwrap(), 30);
|
||||||
|
assert_eq!(get_first_lower_than(40, vec![10, 30, 40]).unwrap(), 40);
|
||||||
|
assert_eq!(get_first_lower_than(41, vec![10, 30, 40]).unwrap(), 40);
|
||||||
|
assert_eq!(get_first_lower_than(99, vec![10, 30, 40]).unwrap(), 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_checkpoints() {
|
||||||
|
assert_eq!(get_test_checkpoint(990000), None);
|
||||||
|
assert_eq!(get_test_checkpoint(100000).unwrap().0, 100000);
|
||||||
|
assert_eq!(get_test_checkpoint(110000).unwrap().0, 100000);
|
||||||
|
assert_eq!(get_test_checkpoint(111000).unwrap().0, 1100000);
|
||||||
|
assert_eq!(get_test_checkpoint(112000).unwrap().0, 1100000);
|
||||||
|
|
||||||
|
assert_eq!(get_main_checkpoint(990000), None);
|
||||||
|
assert_eq!(get_main_checkpoint(110000).unwrap().0, 110000);
|
||||||
|
assert_eq!(get_main_checkpoint(111000).unwrap().0, 110000);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -173,8 +173,16 @@ impl LightWallet {
|
|||||||
let mut system_rng = OsRng;
|
let mut system_rng = OsRng;
|
||||||
system_rng.fill(&mut seed_bytes);
|
system_rng.fill(&mut seed_bytes);
|
||||||
} else {
|
} else {
|
||||||
seed_bytes.copy_from_slice(&Mnemonic::from_phrase(seed_phrase.expect("should have a seed phrase"),
|
let phrase = match Mnemonic::from_phrase(seed_phrase.unwrap(), Language::English) {
|
||||||
Language::English).unwrap().entropy());
|
Ok(p) => p,
|
||||||
|
Err(e) => {
|
||||||
|
let e = format!("Error parsing phrase: {}", e);
|
||||||
|
error!("{}", e);
|
||||||
|
return Err(io::Error::new(ErrorKind::InvalidData, e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
seed_bytes.copy_from_slice(&phrase.entropy());
|
||||||
}
|
}
|
||||||
|
|
||||||
// The seed bytes is the raw entropy. To pass it to HD wallet generation,
|
// The seed bytes is the raw entropy. To pass it to HD wallet generation,
|
||||||
@@ -360,8 +368,8 @@ impl LightWallet {
|
|||||||
})?;
|
})?;
|
||||||
utils::write_string(&mut writer, &self.config.chain_name)?;
|
utils::write_string(&mut writer, &self.config.chain_name)?;
|
||||||
|
|
||||||
// While writing the birthday, be sure that we're right, and that we don't
|
// While writing the birthday, get it from the fn so we recalculate it properly
|
||||||
// have a tx that is before the current birthday
|
// in case of rescans etc...
|
||||||
writer.write_u64::<LittleEndian>(self.get_birthday())?;
|
writer.write_u64::<LittleEndian>(self.get_birthday())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -375,8 +383,12 @@ impl LightWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_birthday(&self) -> u64 {
|
pub fn get_birthday(&self) -> u64 {
|
||||||
|
if self.birthday == 0 {
|
||||||
|
self.get_first_tx_block()
|
||||||
|
} else {
|
||||||
cmp::min(self.get_first_tx_block(), self.birthday)
|
cmp::min(self.get_first_tx_block(), self.birthday)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the first block that this wallet has a tx in. This is often used as the wallet's "birthday"
|
// Get the first block that this wallet has a tx in. This is often used as the wallet's "birthday"
|
||||||
// If there are no Txns, then the actual birthday (which is recorder at wallet creation) is returned
|
// If there are no Txns, then the actual birthday (which is recorder at wallet creation) is returned
|
||||||
@@ -388,7 +400,7 @@ impl LightWallet {
|
|||||||
.collect::<Vec<u64>>();
|
.collect::<Vec<u64>>();
|
||||||
blocks.sort();
|
blocks.sort();
|
||||||
|
|
||||||
*blocks.first() // Returns optional
|
*blocks.first() // Returns optional, so if there's no txns, it'll get the activation height
|
||||||
.unwrap_or(&cmp::max(self.birthday, self.config.sapling_activation_height))
|
.unwrap_or(&cmp::max(self.birthday, self.config.sapling_activation_height))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1294,7 +1306,7 @@ impl LightWallet {
|
|||||||
// Print info about the block every 10,000 blocks
|
// Print info about the block every 10,000 blocks
|
||||||
if height % 10_000 == 0 {
|
if height % 10_000 == 0 {
|
||||||
match self.get_sapling_tree() {
|
match self.get_sapling_tree() {
|
||||||
Ok((h, hash, stree)) => info!("Sapling tree at height {}/{} - {}", h, hash, stree),
|
Ok((h, hash, stree)) => info!("Sapling tree at height\n({}, \"{}\",\"{}\"),", h, hash, stree),
|
||||||
Err(e) => error!("Couldn't determine sapling tree: {}", e)
|
Err(e) => error!("Couldn't determine sapling tree: {}", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1331,7 +1343,7 @@ impl LightWallet {
|
|||||||
|
|
||||||
let total_value = tos.iter().map(|to| to.1).sum::<u64>();
|
let total_value = tos.iter().map(|to| to.1).sum::<u64>();
|
||||||
println!(
|
println!(
|
||||||
"0: Creating transaction sending {} ztoshis to {} addresses",
|
"0: Creating transaction sending {} puposhis to {} addresses",
|
||||||
total_value, tos.len()
|
total_value, tos.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1388,10 +1400,10 @@ impl LightWallet {
|
|||||||
let mut builder = Builder::new(height);
|
let mut builder = Builder::new(height);
|
||||||
|
|
||||||
// A note on t addresses
|
// A note on t addresses
|
||||||
// Funds received by t-addresses can't be explicitly spent in ZecWallet.
|
// Funds received by t-addresses can't be explicitly spent in silentdragonlite.
|
||||||
// ZecWallet will lazily consolidate all t address funds into your shielded addresses.
|
// silentdragonlite will lazily consolidate all t address funds into your shielded addresses.
|
||||||
// Specifically, if you send an outgoing transaction that is sent to a shielded address,
|
// Specifically, if you send an outgoing transaction that is sent to a shielded address,
|
||||||
// ZecWallet will add all your t-address funds into that transaction, and send them to your shielded
|
// silentdragonlite will add all your t-address funds into that transaction, and send them to your shielded
|
||||||
// address as change.
|
// address as change.
|
||||||
let tinputs: Vec<_> = self.get_utxos().iter()
|
let tinputs: Vec<_> = self.get_utxos().iter()
|
||||||
.filter(|utxo| utxo.unconfirmed_spent.is_none()) // Remove any unconfirmed spends
|
.filter(|utxo| utxo.unconfirmed_spent.is_none()) // Remove any unconfirmed spends
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
///
|
///
|
||||||
/// In v1.0 of zecwallet-cli, there was a bug that incorrectly derived HD wallet keys after the first key. That is, the
|
/// In v1.0 of silentdragonlite-cli, there was a bug that incorrectly derived HD wallet keys after the first key. That is, the
|
||||||
/// first key, address was correct, but subsequent ones were not.
|
/// first key, address was correct, but subsequent ones were not.
|
||||||
///
|
///
|
||||||
/// The issue was that the 32-byte seed was directly being used to derive then subsequent addresses instead of the
|
/// The issue was that the 32-byte seed was directly being used to derive then subsequent addresses instead of the
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ impl Utxo {
|
|||||||
let mut address_bytes = vec![0; address_len as usize];
|
let mut address_bytes = vec![0; address_len as usize];
|
||||||
reader.read_exact(&mut address_bytes)?;
|
reader.read_exact(&mut address_bytes)?;
|
||||||
let address = String::from_utf8(address_bytes).unwrap();
|
let address = String::from_utf8(address_bytes).unwrap();
|
||||||
assert_eq!(address.chars().take(1).collect::<Vec<char>>()[0], 't');
|
assert_eq!(address.chars().take(1).collect::<Vec<char>>()[0], 'R');
|
||||||
|
|
||||||
let mut txid_bytes = [0; 32];
|
let mut txid_bytes = [0; 32];
|
||||||
reader.read_exact(&mut txid_bytes)?;
|
reader.read_exact(&mut txid_bytes)?;
|
||||||
|
|||||||
@@ -1601,18 +1601,18 @@ fn test_t_derivation() {
|
|||||||
|
|
||||||
// Test the addresses against https://iancoleman.io/bip39/
|
// Test the addresses against https://iancoleman.io/bip39/
|
||||||
let (taddr, pk) = &wallet.get_t_secret_keys()[0];
|
let (taddr, pk) = &wallet.get_t_secret_keys()[0];
|
||||||
assert_eq!(taddr, "t1eQ63fwkQ4n4Eo5uCrPGaAV8FWB2tmx7ui");
|
assert_eq!(taddr, "RXBxhYDg8vSsHVmAGadniQKh3NvzAtzjRe");
|
||||||
assert_eq!(pk, "Kz9ybX4giKag4NtnP1pi8WQF2B2hZDkFU85S7Dciz3UUhM59AnhE");
|
assert_eq!(pk, "UvGDnY7bpsyz9GnRPvMRQTMKHPyCK5k6c2FBiGQcgRSe9xVNuGGs");
|
||||||
|
|
||||||
// Test a couple more
|
// Test a couple more
|
||||||
wallet.add_taddr();
|
wallet.add_taddr();
|
||||||
let (taddr, pk) = &wallet.get_t_secret_keys()[1];
|
let (taddr, pk) = &wallet.get_t_secret_keys()[1];
|
||||||
assert_eq!(taddr, "t1NoS6ZgaUTpmjkge2cVpXGcySasdYDrXqh");
|
assert_eq!(taddr, "RKDGjDoFHf9BfTFuL27voFdqdV7LhWw9rG");
|
||||||
assert_eq!(pk, "KxdmS38pxskS6bbKX43zhTu8ppWckNmWjKsQFX1hwidvhRRgRd3c");
|
assert_eq!(pk, "UqGi6D8rFfdoEtbqhjz1utu1hKLmagY5TBVHWau54pput9HRfYbG");
|
||||||
|
|
||||||
let (zaddr, sk) = &wallet.get_z_private_keys()[0];
|
let (zaddr, sk) = &wallet.get_z_private_keys()[0];
|
||||||
assert_eq!(zaddr, "zs1q6xk3q783t5k92kjqt2rkuuww8pdw2euzy5rk6jytw97enx8fhpazdv3th4xe7vsk6e9sfpawfg");
|
assert_eq!(zaddr, "zs1wp96063hjs496d28e05uz5gavg7mwshhsgglchtan57el88uwa5jfdgk4nd68kda62vgwucfe6z");
|
||||||
assert_eq!(sk, "secret-extended-key-main1qvpa0qr8qqqqpqxn4l054nzxpxzp3a8r2djc7sekdek5upce8mc2j2z0arzps4zv940qeg706hd0wq6g5snzvhp332y6vhwyukdn8dhekmmsk7fzvzkqm6ypc99uy63tpesqwxhpre78v06cx8k5xpp9mrhtgqs5dvp68cqx2yrvthflmm2ynl8c0506dekul0f6jkcdmh0292lpphrksyc5z3pxwws97zd5els3l2mjt2s7hntap27mlmt6w0drtfmz36vz8pgu7ec0twfrq");
|
assert_eq!(sk, "secret-extended-key-main1qvkk0dn2qqqqpqrk6fl6c6fzzrmkhlj59d2c6kkz37hmal6d4dm69ne75xf0exuvnyk6qrjgp6crvdtaehkda2edg0llv488u25vjh5jtldnp53nrphqeexel57a0dn4t2kkcr6uj6y832yg8wsx3wx6t6rk470dynzdx3cp37xdwl9mpe59vj6yqh67x09vea9khzk5wdqkt65c6x9qkuht7nxyetthu0pr7jrwpthzq2ncgm0dvczadqxuhhk5ekua5v5zzw2kydcudu965");
|
||||||
|
|
||||||
assert_eq!(seed_phrase, Some(wallet.get_seed_phrase()));
|
assert_eq!(seed_phrase, Some(wallet.get_seed_phrase()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ mkdir -p target/macOS-silentdragonlite-cli-v$APP_VERSION
|
|||||||
cp target/release/silentdragonlite-cli target/macOS-silentdragonlite-cli-v$APP_VERSION/
|
cp target/release/silentdragonlite-cli target/macOS-silentdragonlite-cli-v$APP_VERSION/
|
||||||
|
|
||||||
# For Windows and Linux, build via docker
|
# For Windows and Linux, build via docker
|
||||||
docker run --rm -v $(pwd)/:/opt/zecwallet-light-cli rustbuild:latest bash -c "cd /opt/zecwallet-light-cli && cargo build --release && SODIUM_LIB_DIR='/opt/libsodium-win64/lib/' cargo build --release --target x86_64-pc-windows-gnu"
|
docker run --rm -v $(pwd)/:/opt/silentdragonlite-light-cli rustbuild:latest bash -c "cd /opt/silentdragonlite-light-cli && cargo build --release && SODIUM_LIB_DIR='/opt/libsodium-win64/lib/' cargo build --release --target x86_64-pc-windows-gnu"
|
||||||
|
|
||||||
# Now sign and zip the binaries
|
# Now sign and zip the binaries
|
||||||
# macOS
|
# macOS
|
||||||
|
|||||||
Reference in New Issue
Block a user