Skip to content

Commit

Permalink
implement --tmp and --dev for wallet (#135)
Browse files Browse the repository at this point in the history
* improve wallet cli doc comments

* implemented `tmp` and `dev` args

* wallet integration test script, using dev

* `tmp` uses an actual temporary directory

* refactor arg `data-path` to `path`, removed outdated comment

---------

Signed-off-by: muraca <mmuraca247@gmail.com>
  • Loading branch information
muraca authored Nov 7, 2023
1 parent 2770b34 commit ac4bf26
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 72 deletions.
83 changes: 40 additions & 43 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,45 +27,45 @@ jobs:
all: true

test:
name: Test and code coverage
needs: [fmt, toml-sort]
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Install tooling
run: |
sudo apt-get install -y protobuf-compiler
protoc --version
- name: Install latest nextest release
uses: taiki-e/install-action@nextest
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
cache-targets: true
cache-on-failure: true
- name: Run tests and print coverage data
run: cargo llvm-cov nextest --json --output-path lcov.json
--ignore-filename-regex "node/" --summary-only &&
echo "Lines coverage " && jq ".data[0].totals.lines.percent" lcov.json
# if the PR is on the same repo, the coverage data can be reported as a comment
- if: github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
name: Generate lcov report
run: cargo llvm-cov report --lcov --output-path lcov.info
--ignore-filename-regex "node/"
- if: github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
name: Report code coverage
uses: romeovs/lcov-reporter-action@master
with:
lcov-file: lcov.info
pr-number: ${{ github.event.pull_request.number }}
delete-old-comments: true
name: Test and code coverage
needs: [fmt, toml-sort]
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Install tooling
run: |
sudo apt-get install -y protobuf-compiler
protoc --version
- name: Install latest nextest release
uses: taiki-e/install-action@nextest
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
cache-targets: true
cache-on-failure: true
- name: Run tests and print coverage data
run: cargo llvm-cov nextest --json --output-path lcov.json
--ignore-filename-regex "node/" --summary-only &&
echo "Lines coverage " && jq ".data[0].totals.lines.percent" lcov.json
# if the PR is on the same repo, the coverage data can be reported as a comment
- if: github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
name: Generate lcov report
run: cargo llvm-cov report --lcov --output-path lcov.info
--ignore-filename-regex "node/"
- if: github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
name: Report code coverage
uses: romeovs/lcov-reporter-action@master
with:
lcov-file: lcov.info
pr-number: ${{ github.event.pull_request.number }}
delete-old-comments: true

clippy:
name: Clippy
Expand Down Expand Up @@ -103,7 +103,4 @@ jobs:
- name: Build
run: cargo build
- name: Run wallet test
run: |
./target/debug/node-template --dev &
sleep 10 &&
./target/debug/tuxedo-template-wallet --endpoint http://localhost:9944
run: ./wallet/test.sh
54 changes: 31 additions & 23 deletions wallet/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,28 @@ use crate::{h256_from_string, keystore::SHAWN_PUB_KEY, output_ref_from_string, D
#[command(about, version)]
pub struct Cli {
#[arg(long, short, default_value_t = DEFAULT_ENDPOINT.to_string())]
/// RPC endpoint of the node that this wallet will connect to
/// RPC endpoint of the node that this wallet will connect to.
pub endpoint: String,

#[arg(long, short)]
/// Path where the wallet data is stored. Wallet data is just keystore at the moment,
/// but will contain a local database of UTXOs in the future.
///
/// Default value is platform specific
pub data_path: Option<PathBuf>,
/// Path where the wallet data is stored. Default value is platform specific.
pub path: Option<PathBuf>,

#[arg(long)]
#[arg(long, verbatim_doc_comment)]
/// Skip the initial sync that the wallet typically performs with the node.
///
/// The wallet will use the latest data it had previously synced.
pub no_sync: bool,

#[arg(long)]
/// A temporary directory will be created to store the configuration and will be deleted at the end of the process.
/// path will be ignored if this is set.
pub tmp: bool,

#[arg(long, verbatim_doc_comment)]
/// Specify a development wallet instance, using a temporary directory (like --tmp).
/// The keystore will contain the development key Shawn.
pub dev: bool,

#[command(subcommand)]
pub command: Option<Command>,
}
Expand All @@ -42,17 +48,18 @@ pub enum Command {
AmoebaDemo,

/// Verify that a particular coin exists.
///
/// Show its value and owner from both chain storage and the local database.
#[command(verbatim_doc_comment)]
VerifyCoin {
/// A hex-encoded output reference
#[arg(value_parser = output_ref_from_string)]
output_ref: OutputRef,
},

/// Spend some coins.
///
/// For now, all outputs in a single transaction go to the same recipient. FixMe: #62
/// For now, all outputs in a single transaction go to the same recipient.
// FixMe: #62
#[command(verbatim_doc_comment)]
SpendCoins(SpendArgs),

/// Insert a private key into the keystore to later use when signing transactions.
Expand All @@ -65,7 +72,7 @@ pub enum Command {
// sync_height: Option<u32>,
},

/// Generate a private key using either some or no password and insert into the keystore
/// Generate a private key using either some or no password and insert into the keystore.
GenerateKey {
/// Initialize a public/private key pair with a password
password: Option<String>,
Expand All @@ -75,16 +82,18 @@ pub enum Command {
ShowKeys,

/// Remove a specific key from the keystore.
/// WARNING! This will permanently delete the private key information. Make sure your
/// keys are backed up somewhere safe.
/// WARNING! This will permanently delete the private key information.
/// Make sure your keys are backed up somewhere safe.
#[command(verbatim_doc_comment)]
RemoveKey {
/// The public key to remove
#[arg(value_parser = h256_from_string)]
pub_key: H256,
},

/// For each key tracked by the wallet, shows the sum of all UTXO values
/// owned by that key. This sum is sometimes known as the "balance".
/// For each key tracked by the wallet, shows the sum of all UTXO values owned by that key.
/// This sum is sometimes known as the "balance".
#[command(verbatim_doc_comment)]
ShowBalance,

/// Show the complete list of UTXOs known to the wallet.
Expand All @@ -95,7 +104,7 @@ pub enum Command {
pub struct SpendArgs {
/// An input to be consumed by this transaction. This argument may be specified multiple times.
/// They must all be coins.
#[arg(long, short, value_parser = output_ref_from_string)]
#[arg(long, short, verbatim_doc_comment, value_parser = output_ref_from_string)]
pub input: Vec<OutputRef>,

// /// All inputs to the transaction will be from this same sender.
Expand All @@ -105,14 +114,13 @@ pub struct SpendArgs {

// https://docs.rs/clap/latest/clap/_derive/_cookbook/typed_derive/index.html
// shows how to specify a custom parsing function
/// Hex encoded address (sr25519 pubkey) of the recipient
#[arg(long, short, value_parser = h256_from_string, default_value = SHAWN_PUB_KEY)]
/// Hex encoded address (sr25519 pubkey) of the recipient.
#[arg(long, short, verbatim_doc_comment, value_parser = h256_from_string, default_value = SHAWN_PUB_KEY)]
pub recipient: H256,

// The `action = Append` allows us to accept the same value multiple times.
/// An output amount. For the transaction to be valid, the outputs must add up to less than
/// the sum of the inputs. The wallet will not enforce this and will gladly send an invalid transaction
/// which will then e rejected by the node.
#[arg(long, short, action = Append)]
/// An output amount. For the transaction to be valid, the outputs must add up to less than the sum of the inputs.
/// The wallet will not enforce this and will gladly send an invalid which will then be rejected by the node.
#[arg(long, short, verbatim_doc_comment, action = Append)]
pub output_amount: Vec<u128>,
}
5 changes: 2 additions & 3 deletions wallet/src/keystore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ pub const SHAWN_PHRASE: &str =
/// The public key corresponding to the default seed above.
pub const SHAWN_PUB_KEY: &str = "d2bf4b844dfefd6772a8843e669f943408966a977e3ae2af1dd78e0f55f4df67";

/// Insert the example "Shawn" key into the keystore for
/// the current session only. This is convenient for ux when developing.
pub fn insert_default_key_for_this_session(keystore: &LocalKeystore) -> anyhow::Result<()> {
/// Insert the example "Shawn" key into the keystore for the current session only.
pub fn insert_development_key_for_this_session(keystore: &LocalKeystore) -> anyhow::Result<()> {
keystore.sr25519_generate_new(KEY_TYPE, Some(SHAWN_PHRASE))?;
Ok(())
}
Expand Down
36 changes: 33 additions & 3 deletions wallet/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,24 @@ async fn main() -> anyhow::Result<()> {
// Parse command line args
let cli = Cli::parse();

// If the user specified --tmp or --dev, then use a temporary directory.
let tmp = cli.tmp || cli.dev;

// Setup the data paths.
let data_path = cli.data_path.unwrap_or_else(default_data_path);
let data_path = match tmp {
true => temp_dir(),
_ => cli.path.unwrap_or_else(default_data_path),
};
let keystore_path = data_path.join("keystore");
let db_path = data_path.join("wallet_database");

// Setup the keystore
let keystore = sc_keystore::LocalKeystore::open(keystore_path.clone(), None)?;

// Insert the example Shawn key so example transactions can be signed.
crate::keystore::insert_default_key_for_this_session(&keystore)?;
if cli.dev {
// Insert the example Shawn key so example transactions can be signed.
crate::keystore::insert_development_key_for_this_session(&keystore)?;
}

// Setup jsonrpsee and endpoint-related information.
// https://github.com/paritytech/jsonrpsee/blob/master/examples/examples/http.rs
Expand Down Expand Up @@ -171,7 +179,20 @@ async fn main() -> anyhow::Result<()> {
log::info!("No Wallet Command invoked. Exiting.");
Ok(())
}
}?;

if tmp {
// Cleanup the temporary directory.
std::fs::remove_dir_all(data_path.clone()).map_err(|e| {
log::warn!(
"Unable to remove temporary data directory at {}\nPlease remove it manually.",
data_path.to_string_lossy()
);
e
})?;
}

Ok(())
}

//TODO move to rpc.rs
Expand Down Expand Up @@ -221,6 +242,15 @@ fn strip_0x_prefix(s: &str) -> &str {
}
}

/// Generate a plaform-specific temporary directory for the wallet
fn temp_dir() -> PathBuf {
// Since it is only used for testing purpose, we don't need a secure temp dir, just a unique one.
std::env::temp_dir().join(format!(
"tuxedo-wallet-{}",
std::time::UNIX_EPOCH.elapsed().unwrap().as_millis(),
))
}

/// Generate the platform-specific default data path for the wallet
fn default_data_path() -> PathBuf {
// This uses the directories crate.
Expand Down
6 changes: 6 additions & 0 deletions wallet/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Integration tests for the Template Wallet.
# Requires a `cargo build` to be run before.

./target/debug/node-template --dev &
sleep 20 &&
./target/debug/tuxedo-template-wallet --dev

0 comments on commit ac4bf26

Please sign in to comment.