diff --git a/Cargo.lock b/Cargo.lock index e0a7710db..3e6508d33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -398,6 +398,29 @@ name = "dtoa" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "easy-jsonrpc" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "easy-jsonrpc-proc-macro 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 10.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "easy-jsonrpc-proc-macro" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "encode_unicode" version = "0.3.5" @@ -530,7 +553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "grin_api" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#fd077a489d7dd1a465dcf231eddc9fcd30c4ba43" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -563,6 +586,7 @@ dependencies = [ name = "grin_apiwallet" version = "1.1.0" dependencies = [ + "easy-jsonrpc 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "grin_api 1.1.0 (git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0)", @@ -570,17 +594,20 @@ dependencies = [ "grin_core 1.1.0 (git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0)", "grin_keychain 1.1.0 (git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0)", "grin_libwallet 1.1.0", + "grin_refwallet 1.1.0", "grin_store 1.1.0 (git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0)", "grin_util 1.1.0 (git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0)", "grin_wallet_config 1.1.0", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "grin_chain" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#fd077a489d7dd1a465dcf231eddc9fcd30c4ba43" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -603,7 +630,7 @@ dependencies = [ [[package]] name = "grin_core" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#fd077a489d7dd1a465dcf231eddc9fcd30c4ba43" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -629,7 +656,7 @@ dependencies = [ [[package]] name = "grin_keychain" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#fd077a489d7dd1a465dcf231eddc9fcd30c4ba43" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -672,7 +699,7 @@ dependencies = [ [[package]] name = "grin_p2p" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#fd077a489d7dd1a465dcf231eddc9fcd30c4ba43" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -692,7 +719,7 @@ dependencies = [ [[package]] name = "grin_pool" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#fd077a489d7dd1a465dcf231eddc9fcd30c4ba43" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -759,7 +786,7 @@ dependencies = [ [[package]] name = "grin_store" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#fd077a489d7dd1a465dcf231eddc9fcd30c4ba43" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "croaring 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -779,7 +806,7 @@ dependencies = [ [[package]] name = "grin_util" version = "1.1.0" -source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#fd077a489d7dd1a465dcf231eddc9fcd30c4ba43" +source = "git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0#1b3eaba3025f92770ba468de9e77ebd1e4a660cd" dependencies = [ "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -853,6 +880,14 @@ dependencies = [ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hmac" version = "0.6.3" @@ -958,6 +993,18 @@ name = "itoa" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "jsonrpc-core" +version = "10.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1782,6 +1829,14 @@ dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "remove_dir_all" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ring" version = "0.13.5" @@ -2035,6 +2090,19 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tempfile" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "term" version = "0.5.1" @@ -2375,6 +2443,11 @@ dependencies = [ "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicode-segmentation" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-width" version = "0.1.5" @@ -2622,6 +2695,8 @@ dependencies = [ "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" "checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" "checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" +"checksum easy-jsonrpc 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0d8eaadf5a9ed73697761ad586140c40aa0837fb5b141a2b04ee9c07eacbfe" +"checksum easy-jsonrpc-proc-macro 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b50f53cc7025979b06da8fde906f948f0fa4665bf840043f4de1e25acee53c97" "checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" "checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" @@ -2649,6 +2724,7 @@ dependencies = [ "checksum grin_store 1.1.0 (git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0)" = "" "checksum grin_util 1.1.0 (git+https://github.com/mimblewimble/grin?branch=milestone/1.1.0)" = "" "checksum h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb2b25a33e231484694267af28fec74ac63b5ccf51ee2065a5e313b834d836e" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "733e1b3ac906631ca01ebb577e9bb0f5e37a454032b9036b5eaea4013ed6f99a" "checksum http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fe67e3678f2827030e89cc4b9e7ecd16d52f132c0b940ab5005f88e821500f6a" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" @@ -2659,6 +2735,7 @@ dependencies = [ "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" +"checksum jsonrpc-core 10.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc15eef5f8b6bef5ac5f7440a957ff95d036e2f98706947741bfc93d1976db4c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" @@ -2750,6 +2827,7 @@ dependencies = [ "checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828" "checksum regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f" "checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" +"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum ripemd160 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "482aa56cc68aaeccdaaff1cc5a72c247da8bbad3beb174ca5741f274c22883fb" "checksum rpassword 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37473170aedbe66ffa3ad3726939ba677d83c646ad4fd99e5b4bc38712f45ec" @@ -2784,6 +2862,7 @@ dependencies = [ "checksum supercow 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "171758edb47aa306a78dfa4ab9aeb5167405bd4e3dc2b64e88f6a84bbe98bd63" "checksum syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)" = "525bd55255f03c816e5d7f615587bd13030c7103354fadb104993dcee6a788ec" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum terminfo 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8e51065bafd2abe106b6036483b69d1741f4a1ec56ce8a2378de341637de689e" @@ -2817,6 +2896,7 @@ dependencies = [ "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" +"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f" diff --git a/apiwallet/Cargo.toml b/apiwallet/Cargo.toml index 236b02086..a9a338339 100644 --- a/apiwallet/Cargo.toml +++ b/apiwallet/Cargo.toml @@ -15,6 +15,7 @@ failure = "0.1" failure_derive = "0.1" log = "0.4" uuid = { version = "0.6", features = ["serde", "v4"] } +easy-jsonrpc = "0.4.1" grin_libwallet = { path = "../libwallet", version = "1.1.0" } grin_wallet_config = { path = "../config", version = "1.1.0" } @@ -25,3 +26,8 @@ grin_chain = { git = "https://github.com/mimblewimble/grin", branch = "milestone grin_util = { git = "https://github.com/mimblewimble/grin", branch = "milestone/1.1.0" } grin_api = { git = "https://github.com/mimblewimble/grin", branch = "milestone/1.1.0" } grin_store = { git = "https://github.com/mimblewimble/grin", branch = "milestone/1.1.0" } + +[dev-dependencies] +grin_refwallet = { path = "../refwallet", version = "1.1.0" } +serde_json = "1" +tempfile = "3.0.7" diff --git a/apiwallet/src/api.rs b/apiwallet/src/api.rs index a9141683c..8f6307e9d 100644 --- a/apiwallet/src/api.rs +++ b/apiwallet/src/api.rs @@ -37,19 +37,495 @@ use uuid::Uuid; use crate::core::core::hash::Hashed; use crate::core::core::Transaction; use crate::core::ser; -use crate::libwallet::internal::{keys, tx, updater}; use crate::keychain::{Identifier, Keychain}; +use crate::libwallet::internal::{keys, tx, updater}; use crate::libwallet::slate::Slate; use crate::libwallet::types::{ AcctPathMapping, BlockFees, CbData, NodeClient, OutputData, OutputLockFn, TxLogEntry, TxLogEntryType, TxWrapper, WalletBackend, WalletInfo, }; +use crate::libwallet::{Error, ErrorKind}; use crate::util; use crate::util::secp::{pedersen, ContextFlag, Secp256k1}; -use crate::libwallet::{Error, ErrorKind}; +use easy_jsonrpc; const USER_MESSAGE_MAX_LEN: usize = 256; +/// Public definition used to generate jsonrpc api for APIOwner. +#[easy_jsonrpc::rpc] +pub trait OwnerApi { + /** + Networked version of [APIOwner::accounts](struct.APIOwner.html#method.accounts). + + # Json rpc example + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "accounts", + "params": [], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Ok": [ + { + "label": "default", + "path": "0200000000000000000000000000000000" + } + ] + }, + "id": 1 + } + # ); + ``` + */ + fn accounts(&self) -> Result, ErrorKind>; + + /** + Networked version of [APIOwner::create_account_path](struct.APIOwner.html#method.create_account_path). + + # Json rpc example + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "create_account_path", + "params": ["account1"], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Ok": "0200000001000000000000000000000000" + }, + "id": 1 + } + # ); + ``` + */ + fn create_account_path(&self, label: &String) -> Result; + + /** + Networked version of [APIOwner::set_active_account](struct.APIOwner.html#method.set_active_account). + + # Json rpc example + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "set_active_account", + "params": ["default"], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Ok": null + }, + "id": 1 + } + # ); + ``` + */ + fn set_active_account(&self, label: &String) -> Result<(), ErrorKind>; + + /** + Networked version of [APIOwner::retrieve_outputs](struct.APIOwner.html#method.retrieve_outputs). + + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "retrieve_outputs", + "params": [false, false, null], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "CallbackImpl": "Error opening wallet" + } + }, + "id": 1 + } + # ); + ``` + */ + fn retrieve_outputs( + &self, + include_spent: bool, + refresh_from_node: bool, + tx_id: Option, + ) -> Result<(bool, Vec<(OutputData, pedersen::Commitment)>), ErrorKind>; + + /** + Networked version of [APIOwner::retrieve_txs](struct.APIOwner.html#method.retrieve_txs). + + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "retrieve_txs", + "params": [false, null, null], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "CallbackImpl": "Error opening wallet" + } + }, + "id": 1 + } + # ); + ``` + */ + fn retrieve_txs( + &self, + refresh_from_node: bool, + tx_id: Option, + tx_slate_id: Option, + ) -> Result<(bool, Vec), ErrorKind>; + + /** + Networked version of [APIOwner::retrieve_summary_info](struct.APIOwner.html#method.retrieve_summary_info). + + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "retrieve_summary_info", + "params": [false, 1], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "CallbackImpl": "Error opening wallet" + } + }, + "id": 1 + } + # ); + ``` + */ + fn retrieve_summary_info( + &self, + refresh_from_node: bool, + minimum_confirmations: u64, + ) -> Result<(bool, WalletInfo), ErrorKind>; + + /** + Networked version of [APIOwner::estimate_initiate_tx](struct.APIOwner.html#method.estimate_initiate_tx). + + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "estimate_initiate_tx", + "params": [null, 0, 0, 10, 0, false], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "CallbackImpl": "Error opening wallet" + } + }, + "id": 1 + } + # ); + ``` + */ + fn estimate_initiate_tx( + &self, + src_acct_name: Option, + amount: u64, + minimum_confirmations: u64, + max_outputs: usize, + num_change_outputs: usize, + selection_strategy_is_use_all: bool, + ) -> Result<(/* total */ u64, /* fee */ u64), ErrorKind>; + + /** + Networked version of [APIOwner::finalize_tx](struct.APIOwner.html#method.finalize_tx). + + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "finalize_tx", + "params": [{ + "amount": 0, + "fee": 0, + "height": 0, + "id": "414bad48-3386-4fa7-8483-72384c886ba3", + "lock_height": 0, + "num_participants": 2, + "participant_data": [], + "tx": { + "body": { + "inputs": [], + "kernels": [], + "outputs": [] + }, + "offset": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "version": 1 + }], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "CallbackImpl": "Error opening wallet" + } + }, + "id": 1 + } + # ); + ``` + */ + fn finalize_tx(&self, slate: Slate) -> Result; + + /** + Networked version of [APIOwner::cancel_tx](struct.APIOwner.html#method.cancel_tx). + + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "cancel_tx", + "params": [null, null], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "CallbackImpl": "Error opening wallet" + } + }, + "id": 1 + } + # ); + ``` + */ + fn cancel_tx(&self, tx_id: Option, tx_slate_id: Option) -> Result<(), ErrorKind>; + + /** + Networked version of [APIOwner::get_stored_tx](struct.APIOwner.html#method.get_stored_tx). + + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "get_stored_tx", + "params": [ + { + "amount_credited": 0, + "amount_debited": 0, + "confirmation_ts": null, + "confirmed": false, + "creation_ts": "2019-03-05T20:49:59.444095Z", + "fee": null, + "id": 10, + "messages": null, + "num_inputs": 0, + "num_outputs": 0, + "parent_key_id": "0000000000000000000000000000000000", + "stored_tx": null, + "tx_slate_id": null, + "tx_type": "TxReceived" + } + ], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Ok": null + }, + "id": 1 + } + # ); + ``` + */ + fn get_stored_tx(&self, entry: &TxLogEntry) -> Result, ErrorKind>; + + /** + Networked version of [APIOwner::post_tx](struct.APIOwner.html#method.post_tx). + + ```no_run + # // This test currently fails on travis + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "post_tx", + "params": [ + { + "body": { + "inputs": [], + "kernels": [], + "outputs": [] + }, + "offset": "0000000000000000000000000000000000000000000000000000000000000000" + }, + false + ], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "ClientCallback": "Posting transaction to node: Request error: Cannot make request: an error occurred trying to connect: Connection refused (os error 61)" + } + }, + "id": 1 + } + # ); + ``` + */ + fn post_tx(&self, tx: &Transaction, fluff: bool) -> Result<(), ErrorKind>; + + /** + Networked version of [APIOwner::verify_slate_messages](struct.APIOwner.html#method.verify_slate_messages). + + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "verify_slate_messages", + "params": [{ + "amount": 0, + "fee": 0, + "height": 0, + "id": "414bad48-3386-4fa7-8483-72384c886ba3", + "lock_height": 0, + "num_participants": 2, + "participant_data": [], + "tx": { + "body": { + "inputs": [], + "kernels": [], + "outputs": [] + }, + "offset": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "version": 1 + }], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Ok": null + }, + "id": 1 + } + # ); + ``` + */ + fn verify_slate_messages(&self, slate: &Slate) -> Result<(), ErrorKind>; + + /** + Networked version of [APIOwner::restore](struct.APIOwner.html#method.restore). + + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "restore", + "params": [], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "CallbackImpl": "Error opening wallet" + } + }, + "id": 1 + } + # ); + ``` + */ + fn restore(&self) -> Result<(), ErrorKind>; + + /** + Networked version of [APIOwner::check_repair](struct.APIOwner.html#method.check_repair). + + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "check_repair", + "params": [false], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "CallbackImpl": "Error opening wallet" + } + }, + "id": 1 + } + # ); + ``` + */ + fn check_repair(&self, delete_unconfirmed: bool) -> Result<(), ErrorKind>; + + /** + Networked version of [APIOwner::node_height](struct.APIOwner.html#method.node_height). + + + ``` + # grin_apiwallet::doctest_helper_json_rpc_owner_assert_response!( + { + "jsonrpc": "2.0", + "method": "node_height", + "params": [], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "CallbackImpl": "Error opening wallet" + } + }, + "id": 1 + } + # ); + ``` + */ + fn node_height(&self) -> Result<(u64, bool), ErrorKind>; +} + /// Functions intended for use by the owner (e.g. master seed holder) of the wallet. pub struct APIOwner where @@ -83,7 +559,7 @@ where /// [`WalletBackend`](../types/trait.WalletBackend.html) trait. /// /// # Returns - /// * An instance of the OwnerAPI holding a reference to the provided wallet + /// * An instance of the OwnerApi holding a reference to the provided wallet /// /// # Example /// ``` ignore @@ -494,7 +970,7 @@ where /// ``` pub fn retrieve_summary_info( - &mut self, + &self, refresh_from_node: bool, minimum_confirmations: u64, ) -> Result<(bool, WalletInfo), Error> { @@ -619,7 +1095,7 @@ where /// ``` pub fn initiate_tx( - &mut self, + &self, src_acct_name: Option<&str>, amount: u64, minimum_confirmations: u64, @@ -706,7 +1182,7 @@ where /// * Total amount to be locked. /// * Transaction fee pub fn estimate_initiate_tx( - &mut self, + &self, src_acct_name: Option<&str>, amount: u64, minimum_confirmations: u64, @@ -745,7 +1221,7 @@ where /// Lock outputs associated with a given slate/transaction pub fn tx_lock_outputs( - &mut self, + &self, slate: &Slate, mut lock_fn: OutputLockFn, ) -> Result<(), Error> { @@ -759,7 +1235,7 @@ where /// sender as well as the private file generate on the first send step. /// Builds the complete transaction and sends it to a grin node for /// propagation. - pub fn finalize_tx(&mut self, slate: &mut Slate) -> Result<(), Error> { + pub fn finalize_tx(&self, slate: &mut Slate) -> Result<(), Error> { let mut w = self.wallet.lock(); w.open_with_credentials()?; let context = w.get_private_context(slate.id.as_bytes())?; @@ -780,11 +1256,7 @@ where /// output if you're recipient), and unlock all locked outputs associated /// with the transaction used when a transaction is created but never /// posted - pub fn cancel_tx( - &mut self, - tx_id: Option, - tx_slate_id: Option, - ) -> Result<(), Error> { + pub fn cancel_tx(&self, tx_id: Option, tx_slate_id: Option) -> Result<(), Error> { let mut w = self.wallet.lock(); w.open_with_credentials()?; let parent_key_id = w.parent_key_id(); @@ -826,14 +1298,14 @@ where } /// Verifies all messages in the slate match their public keys - pub fn verify_slate_messages(&mut self, slate: &Slate) -> Result<(), Error> { + pub fn verify_slate_messages(&self, slate: &Slate) -> Result<(), Error> { let secp = Secp256k1::with_caps(ContextFlag::VerifyOnly); slate.verify_messages(&secp)?; Ok(()) } /// Attempt to restore contents of wallet - pub fn restore(&mut self) -> Result<(), Error> { + pub fn restore(&self) -> Result<(), Error> { let mut w = self.wallet.lock(); w.open_with_credentials()?; w.restore()?; @@ -842,7 +1314,7 @@ where } /// Attempt to check and fix the contents of the wallet - pub fn check_repair(&mut self, delete_unconfirmed: bool) -> Result<(), Error> { + pub fn check_repair(&self, delete_unconfirmed: bool) -> Result<(), Error> { let mut w = self.wallet.lock(); w.open_with_credentials()?; self.update_outputs(&mut w, true); @@ -852,7 +1324,7 @@ where } /// Retrieve current height from node - pub fn node_height(&mut self) -> Result<(u64, bool), Error> { + pub fn node_height(&self) -> Result<(u64, bool), Error> { let res = { let mut w = self.wallet.lock(); w.open_with_credentials()?; @@ -881,6 +1353,241 @@ where } } +impl OwnerApi for APIOwner +where + W: WalletBackend, + C: NodeClient, + K: Keychain, +{ + fn accounts(&self) -> Result, ErrorKind> { + APIOwner::accounts(self).map_err(|e| e.kind()) + } + + fn create_account_path(&self, label: &String) -> Result { + APIOwner::create_account_path(self, label).map_err(|e| e.kind()) + } + + fn set_active_account(&self, label: &String) -> Result<(), ErrorKind> { + APIOwner::set_active_account(self, label).map_err(|e| e.kind()) + } + + fn retrieve_outputs( + &self, + include_spent: bool, + refresh_from_node: bool, + tx_id: Option, + ) -> Result<(bool, Vec<(OutputData, pedersen::Commitment)>), ErrorKind> { + APIOwner::retrieve_outputs(self, include_spent, refresh_from_node, tx_id) + .map_err(|e| e.kind()) + } + + fn retrieve_txs( + &self, + refresh_from_node: bool, + tx_id: Option, + tx_slate_id: Option, + ) -> Result<(bool, Vec), ErrorKind> { + APIOwner::retrieve_txs(self, refresh_from_node, tx_id, tx_slate_id).map_err(|e| e.kind()) + } + + fn retrieve_summary_info( + &self, + refresh_from_node: bool, + minimum_confirmations: u64, + ) -> Result<(bool, WalletInfo), ErrorKind> { + APIOwner::retrieve_summary_info(self, refresh_from_node, minimum_confirmations) + .map_err(|e| e.kind()) + } + + fn estimate_initiate_tx( + &self, + src_acct_name: Option, + amount: u64, + minimum_confirmations: u64, + max_outputs: usize, + num_change_outputs: usize, + selection_strategy_is_use_all: bool, + ) -> Result<(/* total */ u64, /* fee */ u64), ErrorKind> { + APIOwner::estimate_initiate_tx( + self, + src_acct_name.as_ref().map(String::as_str), + amount, + minimum_confirmations, + max_outputs, + num_change_outputs, + selection_strategy_is_use_all, + ) + .map_err(|e| e.kind()) + } + + fn finalize_tx(&self, mut slate: Slate) -> Result { + APIOwner::finalize_tx(self, &mut slate).map_err(|e| e.kind())?; + Ok(slate) + } + + fn cancel_tx(&self, tx_id: Option, tx_slate_id: Option) -> Result<(), ErrorKind> { + APIOwner::cancel_tx(self, tx_id, tx_slate_id).map_err(|e| e.kind()) + } + + fn get_stored_tx(&self, entry: &TxLogEntry) -> Result, ErrorKind> { + APIOwner::get_stored_tx(self, entry).map_err(|e| e.kind()) + } + + fn post_tx(&self, tx: &Transaction, fluff: bool) -> Result<(), ErrorKind> { + APIOwner::post_tx(self, tx, fluff).map_err(|e| e.kind()) + } + + fn verify_slate_messages(&self, slate: &Slate) -> Result<(), ErrorKind> { + APIOwner::verify_slate_messages(self, slate).map_err(|e| e.kind()) + } + + fn restore(&self) -> Result<(), ErrorKind> { + APIOwner::restore(self).map_err(|e| e.kind()) + } + + fn check_repair(&self, delete_unconfirmed: bool) -> Result<(), ErrorKind> { + APIOwner::check_repair(self, delete_unconfirmed).map_err(|e| e.kind()) + } + + fn node_height(&self) -> Result<(u64, bool), ErrorKind> { + APIOwner::node_height(self).map_err(|e| e.kind()) + } +} + +/// Public definition used to generate jsonrpc api for APIForeign. +#[easy_jsonrpc::rpc] +pub trait ForeignApi { + /** + Networked version of [APIForeign::build_coinbase](struct.APIForeign.html#method.build_coinbase). + + # Json rpc example + + ``` + # grin_apiwallet::doctest_helper_json_rpc_foreign_assert_response!( + { + "jsonrpc": "2.0", + "method": "build_coinbase", + "params": [ + { + "fees": 0, + "height": 0, + "key_id": null + } + ], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "CallbackImpl": "Error opening wallet" + } + }, + "id": 1 + } + # ); + ``` + */ + fn build_coinbase(&self, block_fees: &BlockFees) -> Result; + + /** + Networked version of [APIForeign::verify_slate_messages](struct.APIForeign.html#method.verify_slate_messages). + + # Json rpc example + + ``` + # grin_apiwallet::doctest_helper_json_rpc_foreign_assert_response!( + { + "jsonrpc": "2.0", + "method": "verify_slate_messages", + "params": [ + { + "amount": 0, + "fee": 0, + "height": 0, + "id": "414bad48-3386-4fa7-8483-72384c886ba3", + "lock_height": 0, + "num_participants": 2, + "participant_data": [], + "tx": { + "body": { + "inputs": [], + "kernels": [], + "outputs": [] + }, + "offset": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "version": 1 + } + ], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Ok": null + }, + "id": 1 + } + # ); + ``` + */ + fn verify_slate_messages(&self, slate: &Slate) -> Result<(), ErrorKind>; + + /** + Networked version of [APIForeign::receive_tx](struct.APIForeign.html#method.receive_tx). + + # Json rpc example + + ``` + # grin_apiwallet::doctest_helper_json_rpc_foreign_assert_response!( + { + "jsonrpc": "2.0", + "method": "receive_tx", + "params": [ + { + "amount": 0, + "fee": 0, + "height": 0, + "id": "414bad48-3386-4fa7-8483-72384c886ba3", + "lock_height": 0, + "num_participants": 2, + "participant_data": [], + "tx": { + "body": { + "inputs": [], + "kernels": [], + "outputs": [] + }, + "offset": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "version": 1 + }, + null, + null + ], + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "Err": { + "CallbackImpl": "Error opening wallet" + } + }, + "id": 1 + } + # ); + ``` + */ + fn receive_tx( + &self, + slate: Slate, + dest_acct_name: Option, + message: Option, + ) -> Result; +} + /// Wrapper around external API functions, intended to communicate /// with other parties pub struct APIForeign @@ -912,7 +1619,7 @@ where } /// Build a new (potential) coinbase transaction in the wallet - pub fn build_coinbase(&mut self, block_fees: &BlockFees) -> Result { + pub fn build_coinbase(&self, block_fees: &BlockFees) -> Result { let mut w = self.wallet.lock(); w.open_with_credentials()?; let res = updater::build_coinbase(&mut *w, block_fees); @@ -921,7 +1628,7 @@ where } /// Verifies all messages in the slate match their public keys - pub fn verify_slate_messages(&mut self, slate: &Slate) -> Result<(), Error> { + pub fn verify_slate_messages(&self, slate: &Slate) -> Result<(), Error> { let secp = Secp256k1::with_caps(ContextFlag::VerifyOnly); slate.verify_messages(&secp)?; Ok(()) @@ -929,7 +1636,7 @@ where /// Receive a transaction from a sender pub fn receive_tx( - &mut self, + &self, slate: &mut Slate, dest_acct_name: Option<&str>, message: Option, @@ -970,3 +1677,146 @@ where Ok(()) } } + +impl ForeignApi for APIForeign +where + W: WalletBackend, + C: NodeClient, + K: Keychain, +{ + fn build_coinbase(&self, block_fees: &BlockFees) -> Result { + APIForeign::build_coinbase(self, block_fees).map_err(|e| e.kind()) + } + + fn verify_slate_messages(&self, slate: &Slate) -> Result<(), ErrorKind> { + APIForeign::verify_slate_messages(self, slate).map_err(|e| e.kind()) + } + + fn receive_tx( + &self, + mut slate: Slate, + dest_acct_name: Option, + message: Option, + ) -> Result { + APIForeign::receive_tx( + self, + &mut slate, + dest_acct_name.as_ref().map(String::as_str), + message, + ) + .map_err(|e| e.kind())?; + Ok(slate) + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! doctest_helper_json_rpc_owner_assert_response { + ($request:tt, $expected_response:tt) => { + // create temporary wallet, run jsonrpc request on owner api of wallet, delete wallet, return + // json response. + // In order to prevent leaking tempdirs, This function should not panic. + fn rpc_owner_result( + request: serde_json::Value, + ) -> Result, String> { + use easy_jsonrpc::Handler; + use grin_apiwallet::api::{APIOwner, OwnerApi}; + use grin_keychain::ExtKeychain; + use grin_refwallet::{HTTPNodeClient, LMDBBackend, WalletBackend}; + use grin_util::Mutex; + use grin_wallet_config::WalletConfig; + use serde_json; + use std::sync::Arc; + use tempfile::tempdir; + + let dir = tempdir().map_err(|e| format!("{:#?}", e))?; + { + let mut wallet_config = WalletConfig::default(); + wallet_config.data_file_dir = dir + .path() + .to_str() + .ok_or("Failed to convert tmpdir path to string.".to_owned())? + .to_owned(); + let node_client = + HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); + let wallet: Arc>> = + Arc::new(Mutex::new( + LMDBBackend::new(wallet_config.clone(), "", node_client) + .map_err(|e| format!("{:#?}", e))?, + )); + let api_owner = APIOwner::new(wallet); + let owner_api = &api_owner as &dyn OwnerApi; + Ok(owner_api.handle_request(request)) + } + } + + let response = rpc_owner_result(serde_json::json!($request)) + .unwrap() + .unwrap(); + let expected_response = serde_json::json!($expected_response); + + if response != expected_response { + panic!( + "(left != right) \nleft: {}\nright: {}", + serde_json::to_string_pretty(&response).unwrap(), + serde_json::to_string_pretty(&expected_response).unwrap() + ); + } + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! doctest_helper_json_rpc_foreign_assert_response { + ($request:tt, $expected_response:tt) => { + // create temporary wallet, run jsonrpc request on api of wallet, delete wallet, return + // json response. + // In order to prevent leaking tempdirs, This function should not panic. + fn rpc_owner_result( + request: serde_json::Value, + ) -> Result, String> { + use easy_jsonrpc::Handler; + use grin_apiwallet::api::{APIForeign, ForeignApi}; + use grin_keychain::ExtKeychain; + use grin_refwallet::{HTTPNodeClient, LMDBBackend, WalletBackend}; + use grin_util::Mutex; + use grin_wallet_config::WalletConfig; + use serde_json; + use std::sync::Arc; + use tempfile::tempdir; + + let dir = tempdir().map_err(|e| format!("{:#?}", e))?; + { + let mut wallet_config = WalletConfig::default(); + wallet_config.data_file_dir = dir + .path() + .to_str() + .ok_or("Failed to convert tmpdir path to string.".to_owned())? + .to_owned(); + let node_client = + HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); + let wallet: Arc>> = + Arc::new(Mutex::new( + LMDBBackend::new(wallet_config.clone(), "", node_client) + .map_err(|e| format!("{:#?}", e))?, + )); + let api_foreign = *APIForeign::new(wallet); + let foreign_api = &api_foreign as &dyn ForeignApi; + Ok(foreign_api.handle_request(request)) + } + } + + let response = rpc_owner_result(serde_json::json!($request)) + .unwrap() + .unwrap(); + let expected_response = serde_json::json!($expected_response); + + if response != expected_response { + panic!( + "(left != right) \nleft: {}\nright: {}", + serde_json::to_string_pretty(&response).unwrap(), + serde_json::to_string_pretty(&expected_response).unwrap() + ); + } + }; +} diff --git a/libwallet/src/error.rs b/libwallet/src/error.rs index e0f51c6af..b7855a1fc 100644 --- a/libwallet/src/error.rs +++ b/libwallet/src/error.rs @@ -30,7 +30,7 @@ pub struct Error { } /// Wallet errors, mostly wrappers around underlying crypto or I/O errors. -#[derive(Clone, Eq, PartialEq, Debug, Fail)] +#[derive(Clone, Eq, PartialEq, Debug, Fail, Serialize, Deserialize)] pub enum ErrorKind { /// Not enough funds #[fail( diff --git a/refwallet/src/controller.rs b/refwallet/src/controller.rs index ca96498b5..e49fa7312 100644 --- a/refwallet/src/controller.rs +++ b/refwallet/src/controller.rs @@ -18,10 +18,10 @@ use crate::adapters::util::get_versioned_slate; use crate::adapters::{FileWalletCommAdapter, HTTPWalletCommAdapter, KeybaseWalletCommAdapter}; use crate::api::{ApiServer, BasicAuthMiddleware, Handler, ResponseFuture, Router, TLSConfig}; +use crate::apiwallet::api::{APIForeign, APIOwner}; use crate::core::core; use crate::core::core::Transaction; use crate::keychain::Keychain; -use crate::apiwallet::api::{APIForeign, APIOwner}; use crate::libwallet::slate::{Slate, VersionedSlate}; use crate::libwallet::types::{ CbData, NodeClient, OutputData, SendTXArgs, TxLogEntry, WalletBackend, WalletInfo, @@ -271,7 +271,7 @@ where pub fn retrieve_summary_info( &self, req: &Request, - mut api: APIOwner, + api: APIOwner, ) -> Result<(bool, WalletInfo), Error> { let mut minimum_confirmations = 1; // TODO - default needed here let params = parse_params(req); @@ -289,7 +289,7 @@ where pub fn node_height( &self, _req: &Request, - mut api: APIOwner, + api: APIOwner, ) -> Result<(u64, bool), Error> { api.node_height() } @@ -319,7 +319,7 @@ where pub fn issue_send_tx( &self, req: Request, - mut api: APIOwner, + api: APIOwner, ) -> Box + Send> { Box::new(parse_body(req).and_then(move |args: SendTXArgs| { let result = api.initiate_tx( @@ -382,7 +382,7 @@ where pub fn finalize_tx( &self, req: Request, - mut api: APIOwner, + api: APIOwner, ) -> Box + Send> { Box::new( parse_body(req).and_then(move |mut slate| match api.finalize_tx(&mut slate) { @@ -398,7 +398,7 @@ where pub fn cancel_tx( &self, req: Request, - mut api: APIOwner, + api: APIOwner, ) -> Box + Send> { let params = parse_params(&req); if let Some(id_string) = params.get("id") { @@ -652,7 +652,7 @@ where fn build_coinbase( &self, req: Request, - mut api: APIForeign, + api: APIForeign, ) -> Box + Send> { Box::new(parse_body(req).and_then(move |block_fees| api.build_coinbase(&block_fees))) } @@ -660,7 +660,7 @@ where fn receive_tx( &self, req: Request, - mut api: APIForeign, + api: APIForeign, ) -> Box + Send> { Box::new(parse_body(req).and_then( //TODO: No way to insert a message from the params