diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..b12e9213 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,75 @@ +# Contributing to Liana + +Anyone is welcome to contribute to Liana regardless of any arbitrary criterion. Contribution are +only judged based on their technical relevance and quality. + +Note that the development of Bitcoin software requires a high level of rigor, so it could take some +time (and backs and forths) to polish a contribution before it's ready for merge. + + +## Communication + +Most of the communication is done on GitHub or on the [`#revault` IRC channel on +Libera](https://web.libera.chat/?channels=#revault). + +If you plan to contribute a non-trivial change, consider discussing it in the IRC channel or in a +Github issue before going forward with the implementation. + + +## Looking for contributions + +If you are looking for first time contributions, you can `git grep` for `FIXME`s and `TODO`s +as well as checking out the [good first issues](https://github.com/revault/liana/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) +on the issue tracker. + + +# Workflow + +The codebase is maintained using the "contributor workflow" where everyone +without exception contributes patch proposals using "pull requests" (PRs). This +facilitates social contribution, easy testing and peer review. + +In general, [commits should be atomic](https://en.wikipedia.org/wiki/Atomic_commit#Atomic_commit_convention) +and diffs should be easy to read. For this reason, do not mix any formatting +fixes or code moves with actual code changes. +Make sure each individual commit is hygienic: that it builds successfully +on its own without warnings, errors, regressions, or test failures. + +Commit messages should be verbose by default consisting of a short subject line, +a blank line and detailed explanatory text as separate paragraph(s), unless the +title alone is self-explanatory. Commit messages should be helpful to people +reading your code in the future, so explain the reasoning for your decisions. For +more guidelines about writing commit messages, see this [blog post](https://cbea.ms/git-commit/). + +If your pull request contains fixup commits (commits that change the same line of code repeatedly) or too fine-grained +commits, you may be asked to [squash](https://git-scm.com/docs/git-rebase#_interactive_mode) your commits +before it will be merged. + +Patchsets should always be focused. For example, a pull request could add a +feature, fix a bug, or refactor code; but not a mixture. Please also avoid super +pull requests which attempt to do too much, are overly large, or overly complex +as this makes review difficult. Instead, prefer opening different focused pull requests. + +Anyone may participate in peer review which is expressed by comments in the pull +request. Typically reviewers will review the code for obvious errors, as well as +test out the patch set and opine on the technical merits of the patch. PR should +be reviewed first on the conceptual level before focusing on code style or grammar +fixes. + +Any new contributed feature must come with tests. Preferably both an integration/functional tests +demonstrating its usage in a blackbox manner (for instance calling an RPC command under different +conditions), as well as unit tests exercising specific parts of the logic (for instance a database +query). + + +# Code + +## Minimum Supported Rust Version + +`minisafed` should always compile and pass tests using **Rust 1.48**. + +## Style + +To avoid endless bikeshedding, just use [`rustfmt`](https://github.com/rust-lang/rustfmt). + +[Clippy](https://github.com/rust-lang/rust-clippy) is also often your friend. diff --git a/README.md b/README.md new file mode 100644 index 00000000..abfc1fdd --- /dev/null +++ b/README.md @@ -0,0 +1,147 @@ +# Liana + +*The missing safety net for your bitcoins*. + + +## About + +Liana is a simple Bitcoin wallet that features a timelocked recovery path for all your coins. That +is, your coins are spendable as with a regular wallet but a secondary key becomes available after a +configurable period of time should the primary one not be accessible anymore. + +Liana can be used for inheritance, where the owner of the coins is holding the primary key and the +heir the secondary one. It can also be leveraged for recovery where a single person is holding both +but different tradeoffs can be made between the backup(s) of the directly accessible and timelocked +keys. + +Liana is still under heavy development. Apart from the regular wallet features that are planned, we +intend to implement the possibility to have multiple keys per spending path (multisig) as well as +multiple timelocked paths (for instance for decaying multisigs). We also intend to switch to using +Taproot as soon as possible, for enhanced privacy. + +**As such please consider Liana to be beta software.** + + +## Usage + +As a Bitcoin wallet, Liana needs to be able to connect to the Bitcoin network. The software has been +developed such as multiple ways to connect to the Bitcoin network may be available. However for now +only the connection through `bitcoind` is implemented. + +Therefore in order to use Liana you need to have Bitcoin Core running on your machine for the +desired network. The `bitcoind` installation may be pruned (note this may affect block chain +rescans) up to the maximum (around 550MB of blocks). + +The minimum supported version of Bitcoin Core is `24.0`. If you don't have Bitcoin Core installed on +your machine yet, you can download it [there](https://bitcoincore.org/en/download/). + +### Installing the software + +TODO: download links + +TODO: link to a longer-form document in the doc/ folder containing the different build methods. + +### Setting up a wallet + +If you are using the GUI, you can just start the program. It will spawn an installer that will guide +you through the process of setting up a new wallet. + +If you are using the daemon, you will need to specify its configuration as a TOML file. There is a +documented example of such a configuration file in the [`contrib/` folder](contrib/lianad_config_example.toml). +Then you can start the daemon like so: +``` +lianad --conf /path/to/your/conf.toml +``` + +#### The script descriptor + +**MAKE SURE TO BACK UP YOUR DESCRIPTOR** + +In Bitcoin, the conditions for spending a certain amount of coins are expressed using a +[Script](https://en.bitcoin.it/wiki/Script). In order to be able to recover your coins, you need to +back up both: +- The Script template, in the form of a standard [Output Script + Descriptor](https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki) +- The private key corresponding to the public key used in the Script + +By so doing, any software that understands the Output Script Descriptor standard will be able to +retrieve your coins. By using your private key you would then be able to sign a transaction spending +them. + +But **without the descriptor you won't be able to recover from your backup**. Note however it is +simpler to have redundancy for your descriptor backup. A thief getting access to it will be able to +learn your balance (and transaction history), but **will not be able to steal your funds**. +Therefore you may afford a greater number of backups of your descriptor(s) and using less secure +mediums than for storing your private key. + +### Using a wallet + +You can use Liana just like a regular wallet. Just be aware that if you are using a relative +timelock (the only type of timelocks supported for now), time starts ticking when you receive a +payment. That is if you want the recovery path to never be available, all coins must be spent +at least once every `N` blocks. (With `N` the configured value of the timelock.) + +For now, only the Ledger and Specter DIY signing devices are supported. We may add the possibility +to use Liana as a "hot" wallet in the future (i.e. with a private key directly on the laptop). + +If you are using the GUI, it should be intuitive what menu to use depending on your intention. If it +is not, bug report are very welcome so [feel free to report it](https://github.com/revault/liana/issues)! :) + +If you are using the daemon, you can use the `liana-cli` binary to send commands to it. It will need +the path to the same configuration as the daemon. You can find a full documentation of the JSONRPC +API exposed by `lianad` at [`doc/API.md`](doc/API.md). For instance: +``` +$ liana-cli --conf ./testnet_config.toml getinfo +{ + "result": { + "blockheight": 2406973, + "descriptors": { + "main": { + "change_desc": "wsh(or_d(pk([92162c45]tpubD6NzVbkrYhZ4WzTf9SsD6h7AH7oQEippXK2KP8qvhMMqFoNeN5YFVi7vRyeRSDGtgd2bPyMxUNmHui8t5yCgszxPPxMafu1VVzDpg9aruYW/1/*),and_v(v:pkh(tpubD6NzVbkrYhZ4Wdgu2yfdmrce5g4fiH1ZLmKhewsnNKupbi4sxjH1ZVAorkBLWSkhsjhg8kiq8C4BrBjMy3SjAKDyDdbuvUa1ToAHbiR98js/1/*),older(2))))#5rx53ql7", + "multi_desc": "wsh(or_d(pk([92162c45]tpubD6NzVbkrYhZ4WzTf9SsD6h7AH7oQEippXK2KP8qvhMMqFoNeN5YFVi7vRyeRSDGtgd2bPyMxUNmHui8t5yCgszxPPxMafu1VVzDpg9aruYW/<0;1>/*),and_v(v:pkh(tpubD6NzVbkrYhZ4Wdgu2yfdmrce5g4fiH1ZLmKhewsnNKupbi4sxjH1ZVAorkBLWSkhsjhg8kiq8C4BrBjMy3SjAKDyDdbuvUa1ToAHbiR98js/<0;1>/*),older(2))))#uact7s3g", + "receive_desc": "wsh(or_d(pk([92162c45]tpubD6NzVbkrYhZ4WzTf9SsD6h7AH7oQEippXK2KP8qvhMMqFoNeN5YFVi7vRyeRSDGtgd2bPyMxUNmHui8t5yCgszxPPxMafu1VVzDpg9aruYW/0/*),and_v(v:pkh(tpubD6NzVbkrYhZ4Wdgu2yfdmrce5g4fiH1ZLmKhewsnNKupbi4sxjH1ZVAorkBLWSkhsjhg8kiq8C4BrBjMy3SjAKDyDdbuvUa1ToAHbiR98js/0/*),older(2))))#d693mvvd" + } + }, + "network": "testnet", + "rescan_progress": null, + "sync": 1.0, + "version": "0.1" + } +} +``` + +Note also that you might connect the GUI to a running `lianad`. If the GUI detects a daemon is +already running, it will plug to it and communicate through the JSONRPC API. + + +### Wallet recovery + +TODO: have a longer form document on recovery through the recovery path. + + +## About the software project + +Liana is an open source project. It is [hosted at Github](https://github.com/revault/liana). + +Contributions are very welcome. For guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md). + +Liana is separated in two main components: the daemon and the Graphical User Interface. + +### Liana daemon + +The daemon contains the core logic of the wallet. It is both a library (a Rust crate) that exposes a +command interface and a standalone UNIX daemon that exposes a JSONRPC API through a Unix Domain +Socket. + +The code for the daemon can be found in the [`src/`](src/) folder at the root of this repository. + +### Liana GUI + +The GUI contains both an installer that guides a user through setting up a Liana wallet, as well as +a graphical interface to the daemon using the [`iced`](https://github.com/iced-rs/iced/) library. + +The code for the GUI can be found in the [`gui/src/`](gui/src) folder. + +## License + +Released under the BSD 3-Clause Licence. See the [LICENCE](LICENCE) file. diff --git a/contrib/lianad_config_example.toml b/contrib/lianad_config_example.toml new file mode 100644 index 00000000..e7145faf --- /dev/null +++ b/contrib/lianad_config_example.toml @@ -0,0 +1,38 @@ +# Whether to run the process as a UNIX daemon (double fork magic) +daemon = false + +# (Optional) Path to the folder where we should store the application data. +# Defaults to `.lianad` in your home folder. +data_dir = "/home/wizardsardine/.lianad" + +# How verbose logging should be (one of "error", "warn", "info", "debug", "trace") +log_level = "debug" + +# The wallet descriptor. It must be a Segwit v0 Pay-To-Witness-Script-Hash (`wsh()`) descriptor +# corresponding to a `or(pk(A),and(pk(B),older(X)))` policy (either public key A can spend immediately +# or public key B can spend after X blocks). +# The public keys must be valid extend keys ("xpubs") ending with a wildcard (i.e. can be derived +# from). The public keys must be multipath expressions with exactly the `0` and `1` derivation indexes, +# that is having a derivation step which is `/<0;1>` before the last step. This is in order to be able +# to derive deposit and change addresses from the same descriptor. +# The extended public keys must be encoded for the network the daemon is to be run (i.e. "xpub"s for the +# main network and "tpub"s for everything else). +# +# YOUR DESCRIPTOR IS UNIQUE AND MUST BE BACKED UP, WITHOUT IT YOU WONT BE ABLE TO RECOVER YOUR FUNDS. +# +main_descriptor = "wsh(or_d(pk([92162c45]tpubD6NzVbkrYhZ4WzTf9SsD6h7AH7oQEippXK2KP8qvhMMqFoNeN5YFVi7vRyeRSDGtgd2bPyMxUNmHui8t5yCgszxPPxMafu1VVzDpg9aruYW/<0;1>/*),and_v(v:pkh(tpubD6NzVbkrYhZ4Wdgu2yfdmrce5g4fiH1ZLmKhewsnNKupbi4sxjH1ZVAorkBLWSkhsjhg8kiq8C4BrBjMy3SjAKDyDdbuvUa1ToAHbiR98js/<0;1>/*),older(2))))#uact7s3g" + +# This section is the configuration related to the Bitcoin backend. +# On what network shall it operate? +# How often should it poll the Bitcoin backend for updates? +[bitcoin_config] +network = "testnet" +poll_interval_secs = 30 + +# This section is specific to the bitcoind implementation of the Bitcoin backend. This is the only +# implementation available for now. +# In order to be able to connect to bitcoind, it needs to know on what port it is listening as well +# as where the authentication cookie is located. +[bitcoind_config] +addr = "127.0.0.1:18332" +cookie_path = "/home/wizardsardine/.bitcoin/testnet3/.cookie" diff --git a/src/bitcoin/d/mod.rs b/src/bitcoin/d/mod.rs index 894b4bb3..65229e8b 100644 --- a/src/bitcoin/d/mod.rs +++ b/src/bitcoin/d/mod.rs @@ -24,7 +24,7 @@ const RPC_SOCKET_TIMEOUT: u64 = 180; // A retry happens every 1 second, this makes us give up after one minute. const BITCOIND_RETRY_LIMIT: usize = 60; -// The minimum bitcoind version that can be used with revaultd. +// The minimum bitcoind version that can be used with lianad. const MIN_BITCOIND_VERSION: u64 = 239900; /// An error in the bitcoind interface. @@ -591,7 +591,7 @@ impl BitcoinD { } pub fn sync_progress(&self) -> f64 { - // TODO: don't harass revaultd, be smarter like in revaultd. + // TODO: don't harass lianad, be smarter like in revaultd. roundup_progress( self.block_chain_info() .get("verificationprogress") diff --git a/src/lib.rs b/src/lib.rs index 9daf1258..5a411824 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -305,7 +305,7 @@ impl DaemonHandle { if config.daemon { log::info!("Daemonizing"); let log_file = data_dir.as_path().join("log"); - let pid_file = data_dir.as_path().join("revaultd.pid"); + let pid_file = data_dir.as_path().join("lianad.pid"); unsafe { daemonize::daemonize(&data_dir, &log_file, &pid_file) .map_err(StartupError::Daemonization)?; diff --git a/tests/test_framework/utils.py b/tests/test_framework/utils.py index f2d90efd..c0b959c7 100644 --- a/tests/test_framework/utils.py +++ b/tests/test_framework/utils.py @@ -174,7 +174,7 @@ class UnixDomainSocketRpc(object): return json.loads(buff) except json.JSONDecodeError: # There is more to read, continue - # FIXME: this is a workaround for large reads taken from revaultd. + # FIXME: this is a workaround for large reads taken from lianad. # We should use the '\n' marker instead since lianad uses that. continue