Browse Source

Merge pull request #36 from adityapk00/master

Merge
checkpoints
Denio 5 years ago
committed by GitHub
parent
commit
a21008f9a2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      README.md
  2. 24
      docker/Dockerfile
  3. 67
      lib/src/commands.rs
  4. 8
      lib/src/lightclient.rs
  5. 4
      lib/src/lightwallet.rs
  6. 13
      lib/src/lightwallet/tests.rs

2
README.md

@ -21,7 +21,7 @@ Run `silentdragonlite-cli help` to see a list of all commands.
### Note Management ### Note Management
silentdragonlite 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: silentdragonlite does automatic note and utxo management, which means it doesn't allow you to manually select which address to send outgoing transactions from. It follows these principles:
* Defaults to sending shielded transactions, even if you're sending to a transparent address * Defaults to sending shielded transactions, even if you're sending to a transparent address
* Sapling funds need at least 4 confirmations before they can be spent * Sapling funds need at least 5 confirmations before they can be spent
* Can select funds from multiple shielded addresses in the same transaction * Can select funds from multiple shielded addresses in the same transaction
* Will automatically shield your transparent funds at the first opportunity * Will automatically shield your transparent funds at the first opportunity
* When sending an outgoing transaction to a shielded address, silentdragonlite can decide to use the transaction to additionally shield your transparent funds (i.e., send your transparent funds to your own shielded address in the same transaction) * When sending an outgoing transaction to a shielded address, silentdragonlite 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)

24
docker/Dockerfile

@ -1,35 +1,41 @@
FROM rust:1.38 FROM ubuntu:16.04
LABEL Description="Rust compile env for Linux + Windows (cross)" LABEL Description="Rust compile env for Linux + Windows (cross)"
RUN apt update RUN apt update
RUN apt install -y build-essential mingw-w64 gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf 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 x86_64-pc-windows-gnu
RUN rustup target add aarch64-unknown-linux-gnu RUN rustup target add aarch64-unknown-linux-gnu
RUN rustup target add armv7-unknown-linux-gnueabihf RUN rustup target add armv7-unknown-linux-gnueabihf
# Append the linker to the cargo config for Windows cross compile # Append the linker to the cargo config for Windows cross compile
RUN echo "[target.x86_64-pc-windows-gnu]" >> /usr/local/cargo/config && \ RUN echo "[target.x86_64-pc-windows-gnu]" >> /root/.cargo/config && \
echo "linker = '/usr/bin/x86_64-w64-mingw32-gcc'" >> /usr/local/cargo/config echo "linker = '/usr/bin/x86_64-w64-mingw32-gcc'" >> /root/.cargo/config
RUN echo "[target.aarch64-unknown-linux-gnu]" >> /usr/local/cargo/config && \ RUN echo "[target.aarch64-unknown-linux-gnu]" >> /root/.cargo/config && \
echo "linker = '/usr/bin/aarch64-linux-gnu-gcc'" >> /usr/local/cargo/config echo "linker = '/usr/bin/aarch64-linux-gnu-gcc'" >> /root/.cargo/config
RUN echo "[target.armv7-unknown-linux-gnueabihf]" >> /usr/local/cargo/config && \ RUN echo "[target.armv7-unknown-linux-gnueabihf]" >> /root/.cargo/config && \
echo "linker = '/usr/bin/arm-linux-gnueabihf-gcc'" >> /usr/local/cargo/config echo "linker = '/usr/bin/arm-linux-gnueabihf-gcc'" >> /root/.cargo/config
ENV CC_x86_64_unknown_linux_musl="gcc" ENV CC_x86_64_unknown_linux_musl="gcc"
ENV CC_aarch64_unknown_linux_gnu="aarch64-linux-gnu-gcc" ENV CC_aarch64_unknown_linux_gnu="aarch64-linux-gnu-gcc"
ENV CC_armv7_unknown_linux_gnueabhihf="arm-linux-gnueabihf-gcc" ENV CC_armv7_unknown_linux_gnueabhihf="arm-linux-gnueabihf-gcc"
# This is a bug fix for the windows cross compiler for Rust. # This is a bug fix for the windows cross compiler for Rust.
RUN cp /usr/x86_64-w64-mingw32/lib/crt2.o /usr/local/rustup/toolchains/1.38.0-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/crt2.o RUN cp /usr/x86_64-w64-mingw32/lib/crt2.o /root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/crt2.o
# For windows cross compilation, use a pre-build binary. Remember to set the # For windows cross compilation, use a pre-build binary. Remember to set the
# SODIUM_LIB_DIR for windows cross compilation # SODIUM_LIB_DIR for windows cross compilation
RUN cd /opt && wget https://download.libsodium.org/libsodium/releases/libsodium-1.0.17-mingw.tar.gz && \ RUN cd /opt && wget https://download.libsodium.org/libsodium/releases/libsodium-1.0.17-mingw.tar.gz && \
tar xvf libsodium-1.0.17-mingw.tar.gz tar xvf libsodium-1.0.17-mingw.tar.gz
RUN apt install -y git
# Cargo fetch the dependencies so we don't download them over and over again # Cargo fetch the dependencies so we don't download them over and over again
RUN cd /tmp && git clone https://github.com/adityapk00/silentdragonlite-light-cli.git && \ RUN cd /tmp && git clone https://github.com/adityapk00/silentdragonlite-light-cli.git && \
cd silentdragonlite-light-cli && \ cd silentdragonlite-light-cli && \

67
lib/src/commands.rs

@ -35,6 +35,26 @@ impl Command for SyncCommand {
} }
} }
struct EncryptionStatusCommand {}
impl Command for EncryptionStatusCommand {
fn help(&self) -> String {
let mut h = vec![];
h.push("Check if the wallet is encrypted and if it is locked");
h.push("Usage:");
h.push("encryptionstatus");
h.push("");
h.join("\n")
}
fn short_help(&self) -> String {
"Check if the wallet is encrypted and if it is locked".to_string()
}
fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String {
lightclient.do_encryption_status().pretty(2)
}
}
struct SyncStatusCommand {} struct SyncStatusCommand {}
impl Command for SyncStatusCommand { impl Command for SyncStatusCommand {
@ -440,9 +460,7 @@ impl Command for SendCommand {
// Check for a single argument that can be parsed as JSON // Check for a single argument that can be parsed as JSON
let send_args = if args.len() == 1 { let send_args = if args.len() == 1 {
// Sometimes on the command line, people use "'" for the quotes, which json::parse doesn't let arg_list = args[0];
// understand. So replace it with double-quotes
let arg_list = args[0].replace("'", "\"");
let json_args = match json::parse(&arg_list) { let json_args = match json::parse(&arg_list) {
Ok(j) => j, Ok(j) => j,
@ -731,27 +749,28 @@ impl Command for QuitCommand {
pub fn get_commands() -> Box<HashMap<String, Box<dyn Command>>> { pub fn get_commands() -> Box<HashMap<String, Box<dyn Command>>> {
let mut map: HashMap<String, Box<dyn Command>> = HashMap::new(); let mut map: HashMap<String, Box<dyn Command>> = HashMap::new();
map.insert("sync".to_string(), Box::new(SyncCommand{})); map.insert("sync".to_string(), Box::new(SyncCommand{}));
map.insert("syncstatus".to_string(), Box::new(SyncStatusCommand{})); map.insert("syncstatus".to_string(), Box::new(SyncStatusCommand{}));
map.insert("rescan".to_string(), Box::new(RescanCommand{})); map.insert("encryptionstatus".to_string(), Box::new(EncryptionStatusCommand{}));
map.insert("help".to_string(), Box::new(HelpCommand{})); map.insert("rescan".to_string(), Box::new(RescanCommand{}));
map.insert("balance".to_string(), Box::new(BalanceCommand{})); map.insert("help".to_string(), Box::new(HelpCommand{}));
map.insert("addresses".to_string(), Box::new(AddressCommand{})); map.insert("balance".to_string(), Box::new(BalanceCommand{}));
map.insert("height".to_string(), Box::new(HeightCommand{})); map.insert("addresses".to_string(), Box::new(AddressCommand{}));
map.insert("export".to_string(), Box::new(ExportCommand{})); map.insert("height".to_string(), Box::new(HeightCommand{}));
map.insert("info".to_string(), Box::new(InfoCommand{})); map.insert("export".to_string(), Box::new(ExportCommand{}));
map.insert("send".to_string(), Box::new(SendCommand{})); map.insert("info".to_string(), Box::new(InfoCommand{}));
map.insert("save".to_string(), Box::new(SaveCommand{})); map.insert("send".to_string(), Box::new(SendCommand{}));
map.insert("quit".to_string(), Box::new(QuitCommand{})); map.insert("save".to_string(), Box::new(SaveCommand{}));
map.insert("list".to_string(), Box::new(TransactionsCommand{})); map.insert("quit".to_string(), Box::new(QuitCommand{}));
map.insert("notes".to_string(), Box::new(NotesCommand{})); map.insert("list".to_string(), Box::new(TransactionsCommand{}));
map.insert("new".to_string(), Box::new(NewAddressCommand{})); map.insert("notes".to_string(), Box::new(NotesCommand{}));
map.insert("seed".to_string(), Box::new(SeedCommand{})); map.insert("new".to_string(), Box::new(NewAddressCommand{}));
map.insert("encrypt".to_string(), Box::new(EncryptCommand{})); map.insert("seed".to_string(), Box::new(SeedCommand{}));
map.insert("decrypt".to_string(), Box::new(DecryptCommand{})); map.insert("encrypt".to_string(), Box::new(EncryptCommand{}));
map.insert("unlock".to_string(), Box::new(UnlockCommand{})); map.insert("decrypt".to_string(), Box::new(DecryptCommand{}));
map.insert("lock".to_string(), Box::new(LockCommand{})); map.insert("unlock".to_string(), Box::new(UnlockCommand{}));
map.insert("fixbip39bug".to_string(), Box::new(FixBip39BugCommand{})); map.insert("lock".to_string(), Box::new(LockCommand{}));
map.insert("fixbip39bug".to_string(), Box::new(FixBip39BugCommand{}));
Box::new(map) Box::new(map)
} }

8
lib/src/lightclient.rs

@ -639,6 +639,14 @@ impl LightClient {
res res
} }
pub fn do_encryption_status(&self) -> JsonValue {
let wallet = self.wallet.read().unwrap();
object!{
"encrypted" => wallet.is_encrypted(),
"locked" => !wallet.is_unlocked_for_spending()
}
}
pub fn do_list_transactions(&self) -> JsonValue { pub fn do_list_transactions(&self) -> JsonValue {
let wallet = self.wallet.read().unwrap(); let wallet = self.wallet.read().unwrap();

4
lib/src/lightwallet.rs

@ -769,7 +769,7 @@ impl LightWallet {
None => true None => true
} }
}) })
.map(|nd| if nd.spent.is_none() && nd.unconfirmed_spent.is_none() { nd.note.value } else { 0 }) .map(|nd| if nd.spent.is_none() { nd.note.value } else { 0 })
.sum::<u64>() .sum::<u64>()
}) })
.sum::<u64>() as u64 .sum::<u64>() as u64
@ -1471,7 +1471,7 @@ impl LightWallet {
if selected_value < u64::from(target_value) { if selected_value < u64::from(target_value) {
let e = format!( let e = format!(
"Insufficient verified funds (have {}, need {:?}). NOTE: funds need {} confirmations before they can be spent.", "Insufficient verified funds (have {}, need {:?}). NOTE: funds need {} confirmations before they can be spent.",
selected_value, target_value, self.config.anchor_offset selected_value, target_value, self.config.anchor_offset + 1
); );
error!("{}", e); error!("{}", e);
return Err(e); return Err(e);

13
lib/src/lightwallet/tests.rs

@ -706,6 +706,12 @@ fn test_z_spend_to_z() {
let branch_id = u32::from_str_radix("76b809bb", 16).unwrap(); let branch_id = u32::from_str_radix("76b809bb", 16).unwrap();
let (ss, so) = get_sapling_params().unwrap(); let (ss, so) = get_sapling_params().unwrap();
// Make sure that the balance exists
{
assert_eq!(wallet.zbalance(None), AMOUNT1);
assert_eq!(wallet.verified_zbalance(None), AMOUNT1);
}
// Create a tx and send to address // Create a tx and send to address
let raw_tx = wallet.send_to_address(branch_id, &ss, &so, let raw_tx = wallet.send_to_address(branch_id, &ss, &so,
vec![(&ext_address, AMOUNT_SENT, Some(outgoing_memo.clone()))]).unwrap(); vec![(&ext_address, AMOUNT_SENT, Some(outgoing_memo.clone()))]).unwrap();
@ -736,6 +742,12 @@ fn test_z_spend_to_z() {
assert_eq!(mem[&sent_txid].outgoing_metadata[0].memo.to_utf8().unwrap().unwrap(), outgoing_memo); assert_eq!(mem[&sent_txid].outgoing_metadata[0].memo.to_utf8().unwrap().unwrap(), outgoing_memo);
} }
{
// The wallet should deduct this from the verified balance. The zbalance still includes it
assert_eq!(wallet.zbalance(None), AMOUNT1);
assert_eq!(wallet.verified_zbalance(None), 0);
}
let mut cb3 = FakeCompactBlock::new(2, block_hash); let mut cb3 = FakeCompactBlock::new(2, block_hash);
cb3.add_tx(&sent_tx); cb3.add_tx(&sent_tx);
wallet.scan_block(&cb3.as_bytes()).unwrap(); wallet.scan_block(&cb3.as_bytes()).unwrap();
@ -751,6 +763,7 @@ fn test_z_spend_to_z() {
// The sent tx should generate change // The sent tx should generate change
assert_eq!(txs[&sent_txid].notes.len(), 1); assert_eq!(txs[&sent_txid].notes.len(), 1);
assert_eq!(txs[&sent_txid].notes[0].note.value, AMOUNT1 - AMOUNT_SENT - fee); assert_eq!(txs[&sent_txid].notes[0].note.value, AMOUNT1 - AMOUNT_SENT - fee);
assert_eq!(wallet.zbalance(None), AMOUNT1 - AMOUNT_SENT - fee);
assert_eq!(txs[&sent_txid].notes[0].is_change, true); assert_eq!(txs[&sent_txid].notes[0].is_change, true);
assert_eq!(txs[&sent_txid].notes[0].spent, None); assert_eq!(txs[&sent_txid].notes[0].spent, None);
assert_eq!(txs[&sent_txid].notes[0].unconfirmed_spent, None); assert_eq!(txs[&sent_txid].notes[0].unconfirmed_spent, None);

Loading…
Cancel
Save